转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/9057297.htmlhtml
原题连接:node
今天考试考了前天的SDOI考题算法
天啊我菜爆,只有T2拿了30分编程
而后考试后半程一直在打T1ide
以为考试思路颇有意思,因而就顺着打下来了函数
我的感受这个是$O(nlog^{2}n)$的,可是在loj上我比claris的程序快了1s多,只不过编程复杂度不止翻倍啊……spa
下面介绍一下个人解法调试
其实最先启发个人是链上的部分分code
定义$pre_{i}$为i前面最近的和i同色的点的下标,咱们把每一个点的pre当作权值,插入一个主席树htm
这样的话,1操做咱们只须要用主席树查$[L,R]$区间内pre<L的点数便可
而后咱们考虑2操做,个人思路是统计每一个点的贡献
对于这两个询问点,咱们假设深度较浅的点为A,较深的为B
咱们分B选的点在A前面仍是后面来讨论
对于点i>A,那么点i的贡献应该是$[pre_{i}<=A]*(A-pre_{i})*(B-i+1)$
这个很好理解,前面布尔表达式是作贡献的前提,后面两个括号一个是左端点A的区间,一个是右端点B的区间
而对于i<=A,式子是相似的:贡献是$(i-pre[i])*(A-i+1+B-i+1)-1$
这里后面减1是由于A,B同时选择i点的状况被贡献了2次,因此要减一下
请选手手动把上面的括号都乘开……而后……
咱们须要维护下面4个变量:$i$的和,$pre_{i}$的和,$i^{2}$的和,以及$i*pre_{i}$的和
因为空间有限,这里不展开写式子了
而当问题扩展到树上的时候……
咱们先把刚才那个pre搬到树上来,
而且把pre的定义变成同色的最近祖先的深度
而且把编号所有改为深度
这两点很是重要,我在调试的时候由于有几处没有把原来序列上的编号改为深度调了半天……
而后把那个主席树也搬上来,维护从i到根的pre信息,这个两个操做都要用
再以颜色为下标建一个树上主席树,$root_{i}$维护i到根的颜色,这个咱们1操做要用
咱们发现这是个随机树
那么每一个点距离链的深度应该会很是小
先考虑1操做,咱们找到两个点的lca,这个能够经过直接暴力爬父亲直到走到链上解决,复杂度$O(logn)$
而后在维护pre的树上查询$pre<deep[lca]$的点的个数
再暴力爬深度较浅的那棵树,爬到lca,查询$lca---r$那条链里是否有这种颜色,以及此次暴力爬是否已经通过了这个元素
而后就获得了答案
这个其实我说的麻烦……能够参考一下代码,挺简单的
而后对于2操做呢……
咱们仍是分开考虑,具体来讲我是这样搞得:
A选择$1-----lca$,B随意选择$1---r$,这样使用刚才链的算法能够统计
A选择$lca----l$,B选择$1----lca$,咱们统计B选择的点和A选择的点,这个把刚才的式子稍微修改一下就能统计
具体来讲,设$l----lca$的长度是L,那么A和B的贡献分别是
$(lca-pre_{i})*(deep[l]-deep[i]+1)$和
$(i-pre_{i})*l$
而后咱们再考虑一种最难处理的状况:A在$lca---l$,B在$lca---r$
而后咱们用和刚才相似的方法能够算B的贡献:$[pre_{i} < deep_{lca}]*(B-i+1)*l$
而后A的贡献的话,因为颜色也是随机的因此每种颜色个数比较少,咱们能够暴力找到$lca---r$上第一个同色点而后算贡献
语言表述可能很让人难以理解……
请参考下面namespace sgt1和deal1&deal2函数来更好的理解上面的式子……
这样的话,咱们的复杂度是$nlogn$*指望距链距离 + $nlogn$ + $n$*指望颜色个数*指望距链深度……比较玄学吧……
下面附上代码,保留了必定注释加强观赏体验……
1 #pragma GCC optimize("O3") 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 #define RG register 8 #define UI unsigned int 9 #define LL long long 10 #define N 100010 11 UI SA,SB,SC; 12 inline UI make() 13 { 14 SA^=SA<<16;SA^=SA>>5;SA^=SA<<1; 15 UI tmp=SA; 16 SA=SB,SB=SC,SC^=SA^tmp; 17 return SC; 18 } 19 int n,col[N],m,q,e,adj[N]; 20 struct edge{int zhong,next;}s[N<<1]; 21 inline void add(int qi,int zhong) 22 {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;} 23 int fa[N],lst[N],pre[N],deep[N]; 24 LL s1,s2,s3;int sz; 25 namespace sgt2 26 { 27 struct node 28 { 29 node *ch[2];int size; 30 }*root[N],*null,mem[N<<5];int tot; 31 inline void init() 32 { 33 root[0]=null=new node(); 34 null->ch[0]=null->ch[1]=null; 35 } 36 inline void ins(node *&o,node *old,int l,int r,int pos) 37 { 38 o=mem+(tot++);o->size=old->size+1; 39 if(l==r)return;RG int mi=l+r>>1; 40 if(pos<=mi)o->ch[1]=old->ch[1],ins(o->ch[0],old->ch[0],l,mi,pos); 41 else o->ch[0]=old->ch[0],ins(o->ch[1],old->ch[1],mi+1,r,pos); 42 } 43 inline void ins(int x,int y){ins(root[x],root[y],1,n,col[x]);} 44 inline int querysz(node *a,node *b,int l,int r,int x) 45 { 46 if(l==r)return b->size - a->size; 47 RG int mi=l+r>>1; 48 if(x<=mi)return querysz(a->ch[0],b->ch[0],l,mi,x); 49 return querysz(a->ch[1],b->ch[1],mi+1,r,x); 50 } 51 inline bool nope(int l,int r,int x) 52 {return querysz(root[fa[l]],root[r],1,n,x)==0;} 53 } 54 namespace sgt1 55 { 56 struct node 57 { 58 node *ch[2];int size; 59 LL sum1,sum2,sum3; 60 }*root[N],*null,mem[N<<5];int tot; 61 inline LL S(int r){return r*(r+1ll)/2;} 62 inline LL S2(int x){return (LL)x*(x+1)*(2*x+1)/6;} 63 inline void ins(node *&o,node *old,int l,int r,int pos,int pr) 64 { 65 o=mem+(tot++); 66 o->size=old->size+1;o->sum1=old->sum1+pos; 67 o->sum2=old->sum2+pr;o->sum3=old->sum3+(LL)pos*pr; 68 if(l==r)return; 69 RG int mi=l+r>>1; 70 if(pr<=mi)o->ch[1]=old->ch[1],ins(o->ch[0],old->ch[0],l,mi,pos,pr); 71 else o->ch[0]=old->ch[0],ins(o->ch[1],old->ch[1],mi+1,r,pos,pr); 72 } 73 inline int querysz(node *a,node *b,int l,int r,int R) 74 { 75 if(l==r)return b->size - a->size; 76 RG int mi=l+r>>1; 77 if(mi<R)return b->ch[0]->size - a->ch[0]->size + querysz(a->ch[1],b->ch[1],mi+1,r,R); 78 return querysz(a->ch[0],b->ch[0],l,mi,R); 79 } 80 inline void query(node *a,node *b,int l,int r,int R) 81 { 82 if(l==r) 83 { 84 sz+=b->size - a->size;s1+=b->sum1 - a->sum1; 85 s2+=b->sum2 - a->sum2;s3+=b->sum3 - a->sum3; 86 return; 87 } 88 RG int mi=l+r>>1; 89 if(mi<R) 90 { 91 sz+=b->ch[0]->size - a->ch[0]->size;s1+=b->ch[0]->sum1 - a->ch[0]->sum1; 92 s2+=b->ch[0]->sum2 - a->ch[0]->sum2;s3+=b->ch[0]->sum3 - a->ch[0]->sum3; 93 query(a->ch[1],b->ch[1],mi+1,r,R); 94 } 95 else query(a->ch[0],b->ch[0],l,mi,R); 96 } 97 inline int deal1(int l,int r) 98 {return querysz(root[fa[l]],root[r],0,n-1,deep[fa[l]]);} 99 inline LL q1(int A,int B) 100 { 101 if(A==B)return 0; 102 sz=s1=s2=s3=0;query(root[A],root[B],0,n-1,A); 103 A=deep[A],B=deep[B]; 104 return (LL)sz*A*B + (sz-s1)*A -s2*(B+1) + s3;//s1仍是应该维护,这个地方无法算 105 } 106 inline LL exq1(int A,int B,int l) 107 { 108 if(A==B)return 0; 109 sz=s1=s2=s3=0;query(root[fa[A]],root[B],0,n-1,fa[A]); 110 //这里应该是要去fa[A]那里,lca那个地方也包含在区间里面,而且lca不能做为B的落点被算进去……?(lca以前在B侧的1--lca被算了) 111 return ( sz*(deep[B]+1ll) - s1 )*l -l; 112 } 113 inline LL q2(int A,int B) 114 {return ( root[A]->sum3 - S2(deep[A]) )*2 + (deep[A]+deep[B]+2ll)*( S(deep[A])-root[A]->sum2 ) - deep[A];} 115 inline LL exq2(int A,int l) 116 {return ( S(deep[A])-root[A]->sum2 ) * l;} 117 inline LL deal2(int l,int r) 118 {return ( (l<r)?q1(l,r):0 )+q2(l,r);} 119 inline void work() 120 {for(RG int i=1;i<=n;++i)ins(root[i],root[i-1],0,n-1,i,pre[i]);} 121 inline void init() 122 {root[0]=null=new node();null->ch[0]=null->ch[1]=null;} 123 inline void ins(int x,int y) 124 {ins(root[x],root[y],0,n-1,deep[x],pre[x]);} 125 } 126 int dfl[N],dfr[N],num; 127 inline void dfs(int rt) 128 { 129 dfl[rt]=++num; 130 RG int i,cur=lst[col[rt]]; 131 pre[rt]=lst[col[rt]];lst[col[rt]]=deep[rt]; 132 sgt1::ins(rt,fa[rt]);sgt2::ins(rt,fa[rt]); 133 for(i=adj[rt];i;i=s[i].next)dfs(s[i].zhong); 134 lst[col[rt]]=cur; 135 dfr[rt]=num; 136 } 137 int vis[N],T; 138 inline int deal1(int l,int r) 139 { 140 ++T; 141 RG int fa1=l,fa2=r,ret=0; 142 while(fa1>m)fa1=fa[fa1]; 143 while(fa2>m)fa2=fa[fa2]; 144 if(fa1==fa2) 145 { 146 while(l^r) 147 if(deep[l] > deep[r]) 148 {if(vis[col[l]]!=T)vis[col[l]]=T,++ret;l=fa[l];} 149 else 150 {if(vis[col[r]]!=T)vis[col[r]]=T,++ret;r=fa[r];} 151 if(vis[col[l]]!=T)vis[col[l]]=T,++ret; 152 return ret; 153 } 154 if(fa1 > fa2)l^=r,r^=l,l^=r,fa1^=fa2,fa2^=fa1,fa1^=fa2; 155 ret=sgt1::deal1(fa1,r); 156 while(l>fa1) 157 { 158 if( vis[col[l]]!=T && sgt2::nope(fa1,r,col[l]) ) 159 vis[col[l]]=T,++ret; 160 l=fa[l]; 161 } 162 return ret; 163 } 164 int sta[30],cnt; 165 #include <vector> 166 vector<int>cont[N]; 167 inline int calc(int pos,int lca,int r,int x) 168 { 169 if(col[lca]==x)return 0; 170 int ret=deep[r]; 171 for(vector<int>::iterator it=cont[x].begin();it!=cont[x].end();++it) 172 if(deep[*it] >=deep[lca] && dfl[*it]<=dfl[r] && dfr[r] <=dfr[*it]) 173 ret=min(ret,deep[*it]-1); 174 return ret-deep[lca]; 175 } 176 inline LL deal2(int l,int r) 177 { 178 ++T; 179 RG int fa1=l,fa2=r,lca; 180 LL ret=0; 181 while(fa1>m)fa1=fa[fa1]; 182 while(fa2>m)fa2=fa[fa2]; 183 if(fa1==fa2) 184 { 185 for(fa1=l,fa2=r;l^r;) 186 if(deep[l] > deep[r])l=fa[l];else r=fa[r]; 187 lca=l;l=fa1,r=fa2; 188 } 189 else 190 { 191 if(fa1 > fa2)l^=r,r^=l,l^=r,fa1^=fa2,fa2^=fa1,fa1^=fa2; 192 lca=fa1; 193 } 194 int l1=deep[l]-deep[lca]; 195 ret=sgt1::deal2(lca,r) //A在1---r all 196 + sgt1::q1(lca,l) //A在lca---l,B在1--lca A侧的贡献 197 + sgt1::exq2(lca,l1) //A在lca---l,B在1--lca B侧的贡献 198 + sgt1::exq1(lca,r,l1);//A在lca---l,B在lca--r B侧的贡献 199 cnt=0; 200 fa1=l; 201 while(l>lca)sta[++cnt]=l,l=fa[l]; 202 for(RG int i=cnt;i;--i) 203 { 204 l=sta[i]; 205 if(vis[col[l]]!=T) 206 vis[col[l]]=T,ret+=(LL)calc(l,lca,r,col[l])*(deep[fa1]-deep[l]+1); 207 } 208 return ret; 209 } 210 int main() 211 { 212 RG int i,j,t,l,r,opt; 213 scanf("%d",&t); 214 sgt1::init(); 215 sgt2::init(); 216 while(t--) 217 { 218 scanf("%d%d%u%u%u",&n,&m,&SA,&SB,&SC); 219 for(i=2;i<=m;++i)fa[i]=i-1; 220 for(i=m+1;i<=n;++i)fa[i]=make()%(i-1)+1; 221 for(i=1;i<=n;++i)col[i]=make()%n+1; 222 for(i=1;i<=n;++i)cont[i].clear(); 223 for(i=1;i<=n;++i)cont[col[i]].push_back(i); 224 memset(lst,0,n+1<<2); 225 num=0; 226 if(m==n) 227 { 228 for(i=1;i<=n;++i) 229 pre[i]=lst[col[i]],lst[col[i]]=i; 230 sgt1::tot=0; 231 sgt1::work(); 232 scanf("%d",&q); 233 for(i=1;i<=n;++i)deep[i]=i; 234 for(i=1;i<=q;++i) 235 { 236 scanf("%d%d%d",&opt,&l,&r); 237 if(l>r)l^=r,r^=l,l^=r; 238 if(opt==1)printf("%d\n",sgt1::deal1(l,r)); 239 else printf("%lld\n",sgt1::deal2(l,r)); 240 } 241 } 242 else 243 { 244 e=0;memset(adj,0,sizeof(adj)); 245 for(i=1;i<=n;++i)deep[i]=deep[fa[i]]+1; 246 for(i=2;i<=n;++i)add(fa[i],i); 247 sgt1::tot=sgt2::tot=0;dfs(1); 248 scanf("%d",&q); 249 for(i=1;i<=q;++i) 250 { 251 scanf("%d%d%d",&opt,&l,&r); 252 if(l>r)l^=r,r^=l,l^=r; 253 if(opt==1)printf("%d\n",deal1(l,r)); 254 else printf("%lld\n",deal2(l,r)); 255 } 256 } 257 } 258 }