Serega and Fun Codeforces - 455D || queue
https://codeforces.com/problemset/problem/455/D
其实方法很多,然而当初一个也想不到...
1.分块,块内用链表维护
修改[l,r]就当成删除第r个元素,在第l个元素之前插入删掉的元素:就找到r删除,然后调整各个块的结构(对于[block[l]+1,block[r]]中的每个块,把它之前一块的最后一个元素移到自身块的第一个元素),然后找到l应该插入的位置并插入l
修改的同时,维护一下各个块中各个元素出现的次数
查询应该没什么问题了。。。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 const int bs=300; 14 int cnt;//块数 15 struct E 16 { 17 int pre,nxt;int d; 18 }e[100100]; 19 int he[355],ta[355];//head,tail 20 int bl[100100],st[355],ed[355]; 21 int num[355][100100]; 22 void add_tail(int b,int x) 23 { 24 if(!ta[b]) 25 { 26 he[b]=ta[b]=x; 27 } 28 else 29 { 30 e[ta[b]].nxt=x;e[x].pre=ta[b]; 31 ta[b]=x; 32 } 33 ++num[b][e[x].d]; 34 } 35 int remove_tail(int b) 36 { 37 int t=ta[b]; 38 --num[b][e[t].d]; 39 if(he[b]==ta[b]) 40 { 41 he[b]=ta[b]=0; 42 } 43 else 44 { 45 ta[b]=e[t].pre; 46 e[e[t].pre].nxt=0;e[t].pre=0; 47 } 48 return t; 49 } 50 void add_head(int b,int x) 51 { 52 if(!he[b]) 53 { 54 he[b]=ta[b]=x; 55 } 56 else 57 { 58 e[he[b]].pre=x;e[x].nxt=he[b]; 59 he[b]=x; 60 } 61 ++num[b][e[x].d]; 62 } 63 void ins_before(int b,int x,int y)//ins x to b before y 64 { 65 if(!he[b]) 66 { 67 he[b]=ta[b]=x; 68 } 69 else if(y==he[b]) 70 { 71 e[y].pre=x; 72 e[x].nxt=y; 73 he[b]=x; 74 } 75 else if(!y) 76 { 77 e[ta[b]].nxt=x; 78 e[x].pre=ta[b]; 79 ta[b]=x; 80 } 81 else 82 { 83 e[e[y].pre].nxt=x; 84 e[x].pre=e[y].pre; 85 e[y].pre=x; 86 e[x].nxt=y; 87 } 88 } 89 int qq; 90 int n,an,lans; 91 int main() 92 { 93 //freopen("/tmp/YALI(10-23)/sample/queue/queue1.in","r",stdin); 94 //freopen("/tmp/YALI(10-23)/sample/queue/queue1.out","w",stdout); 95 int i,j,t,l,r,x,nl,nr,nt,b,idx; 96 scanf("%d",&n); 97 for(i=1;i<=n;i++) 98 { 99 scanf("%d",&t); 100 bl[i]=(i-1)/bs; 101 e[i].d=t; 102 } 103 cnt=(n-1)/bs; 104 for(i=0;i<cnt;i++) 105 { 106 st[i]=bs*i+1; 107 ed[i]=bs*(i+1); 108 } 109 st[cnt]=bs*cnt+1;ed[cnt]=n; 110 for(i=1;i<=n;i++) add_tail(bl[i],i); 111 scanf("%d",&qq); 112 while(qq--) 113 { 114 scanf("%d",&idx); 115 if(idx==1) 116 { 117 scanf("%d%d",&l,&r); 118 l=(l+lans-1)%n+1; 119 r=(r+lans-1)%n+1; 120 if(l>r) swap(l,r); 121 /* 122 if(bl[l]==bl[r]) 123 { 124 b=bl[r]; 125 nr=he[b]; 126 for(j=st[b]+1;j<=r;j++) 127 nr=e[nr].nxt; 128 129 } 130 else 131 */ 132 { 133 b=bl[r]; 134 nr=he[b]; 135 for(j=st[b]+1;j<=r;j++) 136 nr=e[nr].nxt; 137 if(nr==he[b]) he[b]=e[nr].nxt; 138 else e[e[nr].pre].nxt=e[nr].nxt; 139 if(nr==ta[b]) ta[b]=e[nr].pre; 140 else e[e[nr].nxt].pre=e[nr].pre; 141 e[nr].pre=e[nr].nxt=0; 142 --num[b][e[nr].d]; 143 b=bl[l]; 144 for(j=bl[r];j>b;j--) 145 { 146 nt=remove_tail(j-1); 147 add_head(j,nt); 148 } 149 if(l==ed[b]) 150 { 151 nl=0; 152 } 153 else 154 { 155 nl=ta[b]; 156 for(j=ed[b]-2;j>=l;j--) 157 nl=e[nl].pre; 158 } 159 ins_before(b,nr,nl); 160 ++num[b][e[nr].d]; 161 } 162 } 163 else 164 { 165 scanf("%d%d%d",&l,&r,&x); 166 l=(l+lans-1)%n+1; 167 r=(r+lans-1)%n+1; 168 x=(x+lans-1)%n+1; 169 if(l>r) swap(l,r); 170 an=0; 171 if(bl[l]==bl[r]) 172 { 173 b=bl[l]; 174 nl=he[b]; 175 for(j=st[b]+1;j<=l;j++) 176 nl=e[nl].nxt; 177 for(j=l;j<=r;j++) 178 { 179 an+=(e[nl].d==x); 180 nl=e[nl].nxt; 181 } 182 } 183 else 184 { 185 for(j=bl[l]+1;j<=bl[r]-1;j++) 186 an+=num[j][x]; 187 b=bl[r]; 188 nr=he[b]; 189 an+=(e[nr].d==x); 190 for(j=st[b]+1;j<=r;j++) 191 { 192 nr=e[nr].nxt; 193 an+=(e[nr].d==x); 194 } 195 b=bl[l]; 196 nl=ta[b]; 197 an+=(e[nl].d==x); 198 for(j=ed[b]-1;j>=l;j--) 199 { 200 nl=e[nl].pre; 201 an+=(e[nl].d==x); 202 } 203 } 204 lans=an; 205 printf("%d\n",an); 206 } 207 } 208 return 0; 209 }
2.分块,定期重构(官方题解)
跟方法1大部分一样,但是块内不用链表,直接用vector或者数组,插入/删除就暴力,同时维护各个块中各个元素出现次数,然后每sqrt(n)次重构所有块
3.平衡树(见官方题解下面的第一条评论)
(额外解释:为什么是n*log^2而不是n*log呢?因为所有的下标都是动态的。询问(l,r,k)时,需要在k-splay中找出有多少个点下标在[l,r]内,而每一次查询下标必须要在0-splay中查询一下(注意下标是动态的,不能直接记下下标))
http://210.33.19.103/contest/1025/problem/3
此题同C.queue