2020-08-03

http://icpc.upc.edu.cn/problem.php?cid=1461&pid=2

题目描述

校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
K=2,读入l,r表示询问l~r之间能见到多少种树
(l,r>0)

输入

第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作

输出

对于每个k=2输出一个答案

样例输入
5 4
1 1 3
2 2 5
1 2 4
2 3 5
样例输出’
1
2
提示

20%的数据保证,n,m<=100
60%的数据保证,n <=1000,m<=50000
100%的数据保证,n,m<=50000
采用括号序列+树状数组来解决这道题目,种树为一个区间,我们可以在种树的起点标记一个左括号,种树的终点标记一个右括号,统计的时候计算终点前左括号的数目和起点前右括号的数目,两个做差即为答案。

#include
using namespace std;
typedef long long ll;
ll c1[500500]={0};
ll c2[500500]={0};
ll n,m;
ll lowbit(ll x)
{
    return x&(-x);
}
ll update1(ll k,ll x)
{
    for(ll i=k;i<=n;i+=lowbit(i))
        c1[i]+=x;
}
ll update2(ll k,ll x)
{
    for(ll i=k;i<=n;i+=lowbit(i))
        c2[i]+=x;
}
ll sum1(ll k)
{
    ll ans=0;
    for(ll i=k;i>=1;i-=lowbit(i))
        ans+=c1[i];
    return ans;
}
ll sum2(ll k)
{
    ll ans=0;
    for(ll i=k;i>=1;i-=lowbit(i))
        ans+=c2[i];
    return ans;
}
int main()
{
    ll a,b,c;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++)
    {
       scanf("%lld%lld%lld",&a,&b,&c);
       if(a==1)
       {
           update1(b,1);  /// 左括号
           update2(c,1);  /// 右括号
       }
       else
       {
           printf("%lldn",sum1(c)-sum2(b-1));
       }
    }
}

http://icpc.upc.edu.cn/problem.php?cid=1461&pid=4

题目描述

有一个n个元素的数组,每个元素初始均为0。有m条指令,要么让其中一段连续序列数字反转——0变1,1变0(操作1),要么询问某个元素的值(操作2)。
例如当n=20时,10条指令如下:
在这里插入图片描述

输入

第一行包含两个整数n,m,表示数组的长度和指令的条数;
以下m行,每行的第一个数t表示操作的种类:
若t=1,则接下来有两个数L,R,表示区间[L,R]的每个数均反转;
若t=2,则接下来只有一个数i,表示询问的下标。

输出

每个操作2输出一行(非0即1),表示每次操作2的回答。

样例输入
20 10
1 1 10
2 6
2 12
1 5 12
2 6
2 15
1 6 16
1 11 17
2 12
2 6
样例输出
1
0
0
0
1
1
提示

对于50%的数据,1≤n≤103,1≤m≤104;
对于100%的数据,1≤n≤105,1≤m≤5×105,保证L≤R。
与上一道题目同,树状数组统计反转次数即可。

#include
using namespace std;
typedef long long ll;
ll c1[500500]={0};
ll c2[500500]={0};
ll p[500500]={0};
ll n,m;
ll lowbit(ll x)
{
    return x&(-x);
}
ll update1(ll k,ll x)
{
    for(ll i=k;i<=n;i+=lowbit(i))
        c1[i]+=x;
}
ll update2(ll k,ll x)
{
    for(ll i=k;i<=n;i+=lowbit(i))
        c2[i]+=x;
}
ll sum1(ll k)
{
    ll ans=0;
    for(ll i=k;i>=1;i-=lowbit(i))
        ans+=c1[i];
    return ans;
}
ll sum2(ll k)
{
    ll ans=0;
    for(ll i=k;i>=1;i-=lowbit(i))
        ans+=c2[i];
    return ans;
}
int main()
{
    ll a,b,c;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++)
    {
       scanf("%lld",&a);
       if(a==1)
       {
           scanf("%lld%lld",&b,&c);
           update1(b,1);  /// 左括号
           update2(c,1);  /// 右括号
       }
       else
       {
           scanf("%lld",&b);
           printf("%lldn",(sum1(b)-sum2(b-1))%2);
       }
    }
}


http://icpc.upc.edu.cn/problem.php?cid=1431&pid=12

题目描述

在给定的N个整数A1,A2……AN中选出两个进行xor运算,得到的结果最大是多少?

输入

第一行一个整数N,第二行N个整数A1~AN。

输出

一个整数表示答案。

样例输入
3
1 2 3
样例输出
3
提示

对于100%的数据: N<=10^5, 0<=Ai<2^31。
用字典树存二进制,找最大的异或值。

#include 
#include 
using namespace std;
typedef long long ll;
int a[1005000]={0};
int tree[5000500][3]={0};
int tot=1;///必须从1开始
int in(int x)
{
    int p=1;
    for(int i=30;i>=0;i--)
    {
        int k=x>>i&1;
        if(tree[p][k]==0)
            tree[p][k]=++tot;
        p=tree[p][k];
    }
}
int out(int x)
{
    int p=1,ans=0;
    for(int i=30;i>=0;i--)
    {
        int k=x>>i&1;
        if(tree[p][!k])
        {
            ans=ans*2+!k;
            p=tree[p][!k];
        }
        else
        {
            ans=ans*2+k;
            p=tree[p][k];
        }
    }
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int max1=0;
    for(int i=1;i<=n;i++)
    {
       in(a[i]);
       int num=out(a[i]);
       max1=max(max1,num^a[i]);
    }
    cout<<max1<<endl;
    return 0;
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注