Xors on Segments Codeforces - 620F

http://codeforces.com/problemset/problem/620/F

此题是莫队,但是不能用一般的莫队做,因为是最优化问题,没有办法在删除元素的时候维护答案。


这题的方法(好像还有个名字叫"回滚莫队“,说明:https://blog.csdn.net/maverickfw/article/details/72988286):

官方题解:http://codeforces.com/blog/entry/22936

设完成一次"加入贡献"的操作的复杂度是O(p)

首先定块大小sz,定每个坐标应该属于的块。

对于左右端点在同一块内的询问,暴力处理即可。每一个询问需要复杂度O(p*sz)

对于其他询问,按左端点所属的块分类。

分类完后,对于同一类的询问,按右端点从小到大排序。对于每一类的询问分开处理。

对于每一类,先把"当前维护区间"的左端点定为 属于该块的坐标 中最靠右的坐标(这样的话,该类询问的左端点都小于等于这个点且离这个点距离不超过sz),右端点定为左端点-1(为了让区间为空)。还要清空当前答案。

对于该类中每一个询问,先照常移动右端点到与询问的右端点相同,然后记下此时的答案,然后把左端点移动到与询问的左端点相同,得到该询问的答案并记录;然后把左端点的移动还原,把答案还原即可(这样就避开了维护答案)

对于每一类,右端点最多有O(n)次移动,而有n/sz类,这一部分复杂度是O(p*n*n/sz);对于每一个询问,额外还要O(p*sz)的复杂度进行左端点的调整

因此,总复杂度是O(p*(n*n/sz+m*sz)),当sz=sqrt(n*n/m)时最小


解决了莫队的问题,还要解决异或最大值维护的问题。这个是用01字典树做的,就不写了。。。看官方题解吧

(大概要支持在01字典树中查询:集合中,对于所有"第二权值"小于等于/大于等于特定值的元素,查询与另一给定值异或的最大值,挺奇怪的)

错误记录:

1.trie没有开垃圾回收,内存不够

2.计算块大小时,没有注意块大小可能变成0

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<set>
  5 #include<queue>
  6 #include<vector>
  7 using namespace std;
  8 int f[2000100];
  9 int n,m,sz,sz1;
 10 //int ttt;
 11 int lft[40];
 12 namespace Trie
 13 {
 14 const int l2n=20;
 15 int sz[4000100],ch[4000100][2],dat[4000100];
 16 multiset<int> ss[4001000];
 17 int x,kkk;
 18 queue<int> qqq;
 19 int getnode()
 20 {
 21     //yttt=max(ttt,int(2000100-qqq.size()));
 22     int t=qqq.front();qqq.pop();
 23     return t;
 24 }
 25 void delnode(int x)
 26 {
 27     qqq.push(x);
 28 }
 29 void deltree(int x)
 30 {
 31     if(!x)    return;
 32     deltree(ch[x][0]);
 33     deltree(ch[x][1]);
 34     ss[x].clear();ch[x][0]=ch[x][1]=dat[x]=sz[x]=0;
 35     delnode(x);
 36 }
 37 void init()
 38 {
 39     int i;
 40     for(i=1;i<4000100;i++)    qqq.push(i);
 41     lft[0]=1;
 42     for(i=1;i<=l2n;i++)    lft[i]=lft[i-1]<<1;
 43 }
 44 int getdat1(int x)    {return x?dat[x]:0x3f3f3f3f;}
 45 void _ins1(int p,int &num)
 46 {
 47     if(!num)    num=getnode(),dat[num]=0x3f3f3f3f;
 48     sz[num]++;
 49     if(p>=0)    _ins1(p-1,ch[num][!!(x&lft[p])]),dat[num]=min(getdat1(ch[num][0]),getdat1(ch[num][1]));
 50     else    ss[num].insert(kkk),dat[num]=*ss[num].begin();
 51 }
 52 void ins1(int d,int kk,int &num)    {x=d;kkk=kk;_ins1(l2n-1,num);}
 53 //ins1维护插入kk的最小值
 54 void _ins2(int p,int &num)
 55 {
 56     if(!num)    num=getnode();
 57     sz[num]++;
 58     if(p>=0)    _ins2(p-1,ch[num][!!(x&lft[p])]),dat[num]=max(dat[ch[num][0]],dat[ch[num][1]]);
 59     else    ss[num].insert(kkk),dat[num]=*ss[num].rbegin();
 60 }
 61 void ins2(int d,int kk,int &num)    {x=d;kkk=kk;_ins2(l2n-1,num);}
 62 //ins2维护插入kk的最大值
 63 
 64 
 65 void _era1(int p,int &num)
 66 {
 67     sz[num]--;
 68     if(p>=0)    _era1(p-1,ch[num][!!(x&lft[p])]),dat[num]=min(getdat1(ch[num][0]),getdat1(ch[num][1]));
 69     else    ss[num].erase(ss[num].find(kkk)),dat[num]=ss[num].empty()?0x3f3f3f3f:*ss[num].begin();
 70 }
 71 void era1(int d,int kk,int &num)    {x=d;kkk=kk;_era1(l2n-1,num);}
 72 void _era2(int p,int &num)
 73 {
 74     sz[num]--;
 75     if(p>=0)    _era2(p-1,ch[num][!!(x&lft[p])]),dat[num]=max(dat[ch[num][0]],dat[ch[num][1]]);
 76     else    ss[num].erase(ss[num].find(kkk)),dat[num]=ss[num].empty()?0:*ss[num].rbegin();
 77 }
 78 void era2(int d,int kk,int &num)    {x=d;kkk=kk;_era2(l2n-1,num);}
 79 
 80 
 81 int que1(int x,int kk,int num)//que1查询维护值小于等于kk的数中与x的xor最大值
 82 {
 83     int ans=0,i;bool t;
 84     for(i=l2n-1;i>=0;--i)
 85     {
 86         t=x&lft[i];
 87         if(sz[ch[num][!t]]&&dat[ch[num][!t]]<=kk)    ans|=lft[i],num=ch[num][!t];
 88         else    num=ch[num][t];
 89     }
 90     return ans;
 91 }
 92 int que2(int x,int kk,int num)//que2查询维护值大于等于kk的数中与x的xor最大值
 93 {
 94     int ans=0,i;bool t;
 95     for(i=l2n-1;i>=0;--i)
 96     {
 97         t=x&lft[i];
 98         if(sz[ch[num][!t]]&&dat[ch[num][!t]]>=kk)    ans|=lft[i],num=ch[num][!t];
 99         else    num=ch[num][t];
100     }
101     return ans;
102 }
103 }
104 using Trie::ins1;using Trie::ins2;
105 using Trie::era1;using Trie::era2;
106 using Trie::que1;using Trie::que2;
107 using Trie::deltree;
108 struct Q
109 {
110     int l,r,num;
111     Q(){}
112     Q(int a,int b,int c):l(a),r(b),num(c){}
113 };
114 int a[50100],ans[5010];
115 int rt1,rt2;
116 int anss;
117 void add1(int p)//加入p的贡献
118 {
119     ins1(f[p-1],p,rt1);ins2(f[p],p,rt2);
120     anss=max(anss,que1(f[p],p,rt1));
121     //printf("a%d\n",f[p]^f[p-1]);
122     anss=max(anss,que2(f[p-1],p,rt2));
123 }
124 void del1(int p)
125 {
126     era1(f[p-1],p,rt1);era2(f[p],p,rt2);
127 }
128 vector<Q> q[1010];
129 bool cmp(const Q &a,const Q &b)    {return a.r<b.r;}
130 int main()
131 {
132     int i,j,j2,l,r,tans;Trie::init();
133     for(i=1;i<=2000000;i++)    f[i]=f[i-1]^i;
134     scanf("%d%d",&n,&m);sz=max(1,int(sqrt(double(n)/m*n)));sz1=(n-1)/sz;
135     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
136     for(i=1;i<=m;i++)
137     {
138         scanf("%d%d",&l,&r);
139         if((l-1)/sz==(r-1)/sz)
140         {
141             deltree(rt1);deltree(rt2);
142             rt1=rt2=anss=0;
143             for(j=l;j<=r;j++)    add1(a[j]);
144             ans[i]=anss;
145             //printf("a%d %d\n",i,ans[i]);
146         }
147         else
148             q[(l-1)/sz].push_back(Q(l,r,i));
149     }
150     for(i=0;i<=sz1;i++)
151     {
152         sort(q[i].begin(),q[i].end(),cmp);
153         l=(i+1)*sz;r=l-1;rt1=rt2=anss=0;
154         for(j=0;j<q[i].size();j++)
155         {
156             while(r<q[i][j].r)    add1(a[++r]);
157             tans=anss;
158             for(j2=l-1;j2>=q[i][j].l;j2--)    add1(a[j2]);
159             ans[q[i][j].num]=anss;
160             for(j2=l-1;j2>=q[i][j].l;j2--)    del1(a[j2]);
161             anss=tans;
162         }
163         deltree(rt1);deltree(rt2);
164     }
165     for(i=1;i<=m;i++)    printf("%d\n",ans[i]);
166     //printf("a%d\n",ttt);
167     return 0;
168 }

 

posted @ 2018-05-09 14:52  hehe_54321  阅读(338)  评论(0编辑  收藏  举报
AmazingCounters.com