http://www.cnblogs.com/BLADEVIL/p/3479713.html
这个大神写的特别好……难得的是还是p党(感动)
[ZJOI2008]树的统计Count
线段树只需要单点修改……
type arr1=record toward,next:longint; end; arr2=record left,right,max,sum:longint; end; const mm=500000; var tree:array[0..mm]of arr2; edge:array[0..mm]of arr1; first,num,value,top,hash,fa,size,maxson,dep:array[0..mm]of longint; chose:array[0..mm]of boolean; total,tot:longint; function max(x,y:longint):longint; begin if x<y then exit(y); exit(x); end; procedure swap(var x,y:longint); var i:longint; begin i:=x; x:=y; y:=i; end; procedure update(x:longint); begin tree[x].sum:=tree[x<<1].sum+tree[x<<1+1].sum; tree[x].max:=max(tree[x<<1].max,tree[x<<1+1].max); end; procedure addedge(j,k:longint); begin inc(total); edge[total].toward:=k; edge[total].next:=first[j]; first[j]:=total; end; procedure dfs(x:longint); var i,too:longint; begin chose[x]:=false; i:=first[x]; size[x]:=1; maxson[x]:=0; while i<>0 do begin too:=edge[i].toward; if chose[too] then begin fa[too]:=x; dfs(too); inc(size[x],size[too]); if size[too]>size[maxson[x]] then maxson[x]:=too; end; i:=edge[i].next; end; end; procedure make(x,y,depth:longint); var i,too:longint; begin inc(tot); num[x]:=tot; hash[tot]:=value[x]; chose[x]:=false; top[x]:=y; dep[x]:=depth; if maxson[x]<>0 then make(maxson[x],y,depth); i:=first[x]; while i<>0 do begin too:=edge[i].toward; if (chose[too]) and (too<>maxson[x]) then make(too,too,depth+1); i:=edge[i].next; end; end; procedure build(x,l,r:longint); var mid:longint; begin tree[x].left:=l; tree[x].right:=r; if l=r then begin tree[x].sum:=hash[l]; tree[x].max:=hash[l]; exit; end; mid:=(l+r)>>1; build(x<<1,l,mid); build(x<<1+1,mid+1,r); update(x); end; function askmax(x,ll,rr:longint):longint; var mid:longint; begin if (tree[x].left=ll) and (tree[x].right=rr) then exit(tree[x].max); mid:=(tree[x].left+tree[x].right)>>1; if ll>mid then exit(askmax(x<<1+1,ll,rr)) else if rr<=mid then exit(askmax(x<<1,ll,rr)) else exit(max(askmax(x<<1,ll,mid),askmax(x<<1+1,mid+1,rr))); end; function asksum(x,ll,rr:longint):longint; var mid:longint; begin if (tree[x].left=ll) and (tree[x].right=rr) then exit(tree[x].sum); mid:=(tree[x].left+tree[x].right)>>1; if ll>mid then exit(asksum(x<<1+1,ll,rr)) else if rr<=mid then exit(asksum(x<<1,ll,rr)) else exit(asksum(x<<1,ll,mid)+asksum(x<<1+1,mid+1,rr)); end; procedure change(x,u,z:longint); var mid:longint; begin if (tree[x].left=u) and (tree[x].right=u) then begin tree[x].sum:=z; tree[x].max:=z; exit; end; mid:=(tree[x].left+tree[x].right)>>1; if u>mid then change(x<<1+1,u,z) else change(x<<1,u,z); update(x); end; procedure querymax(x,y:longint); var ans:longint; begin ans:=-100000000; if dep[x]>dep[y] then swap(x,y); while dep[x]<dep[y] do begin ans:=max(ans,askmax(1,num[top[y]],num[y])); y:=fa[top[y]]; end; while top[x]<>top[y] do begin ans:=max(ans,max(askmax(1,num[top[x]],num[x]),askmax(1,num[top[y]],num[y]))); x:=fa[top[x]]; y:=fa[top[y]]; end; x:=num[x]; y:=num[y]; if x>y then swap(x,y); ans:=max(ans,askmax(1,x,y)); writeln(ans); end; procedure querysum(x,y:longint); var ans:longint; begin ans:=0; if dep[x]>dep[y] then swap(x,y); while dep[x]<dep[y] do begin ans:=ans+asksum(1,num[top[y]],num[y]); y:=fa[top[y]]; end; while top[x]<>top[y] do begin ans:=ans+asksum(1,num[top[x]],num[x])+asksum(1,num[top[y]],num[y]); x:=fa[top[x]]; y:=fa[top[y]]; end; x:=num[x]; y:=num[y]; if x>y then swap(x,y); ans:=ans+asksum(1,x,y); writeln(ans); end; procedure into; var i,j,k,n:longint; begin readln(n); total:=0; tot:=0; fillchar(first,sizeof(first),0); for i:=1 to n-1 do begin readln(j,k); addedge(j,k); addedge(k,j); end; for i:=1 to n do read(value[i]); readln; fillchar(size,sizeof(size),0); fillchar(chose,sizeof(chose),true); dfs(1); fillchar(chose,sizeof(chose),true); make(1,1,1); build(1,1,n); end; procedure work; var m,j,k:longint; ch:char; begin readln(m); while m>0 do begin dec(m); read(ch); if ch='Q' then begin read(ch); if ch='M' then begin repeat read(ch); until ch=' '; readln(j,k); querymax(j,k); end else begin repeat read(ch); until ch=' '; readln(j,k); querysum(j,k); end; end else begin repeat read(ch); until ch=' '; readln(j,k); change(1,num[j],k); end; end; end; begin into; work; readln; readln; end.
[SDOI2011]染色
线段树要lazy,好久没写竟然能一次写对。一直wa,最后才发现自己脑袋大开用运算符重载没注意加的顺序。
{$inline on} type arr1=record toward,next:longint; end; arr2=record col1,col2,sum:longint; end; arr3=record left,right,mark:longint; end; const maxn=600000; var tree1:array[0..maxn]of arr2; tree2:array[0..maxn]of arr3; edge:array[0..maxn]of arr1; first,num,hash,col,fa,size,maxson,top,dep:array[0..maxn]of longint; chose:array[0..maxn] of boolean; tot,total,n,m:longint; procedure addedge(j,k:longint);inline; begin inc(total); edge[total].toward:=k; edge[total].next:=first[j]; first[j]:=total; end; procedure swap(var x,y:longint);inline; var i:longint; begin i:=x; x:=y; y:=i; end; procedure dfs(x:longint);inline; var i,too:longint; begin chose[x]:=false; size[x]:=1; i:=first[x]; while i<>0 do begin too:=edge[i].toward; if chose[too] then begin fa[too]:=x; dfs(too); size[x]:=size[x]+size[too]; if size[maxson[x]]<size[too] then maxson[x]:=too; end; i:=edge[i].next; end; end; procedure make(x,y,depth:longint);inline; var i,too:longint; begin chose[x]:=false; inc(tot); num[x]:=tot; hash[tot]:=col[x]; dep[x]:=depth; top[x]:=y; i:=first[x]; if maxson[x]<>0 then make(maxson[x],y,depth); while i<>0 do begin too:=edge[i].toward; if (chose[too]) and (too<>maxson[x]) then make(too,too,depth+1); i:=edge[i].next; end; end; operator +(const lx,rx:arr2)x:arr2;inline; begin if lx.sum=0 then begin x.col1:=rx.col1; x.col2:=rx.col2; x.sum:=rx.sum; end else if rx.sum=0 then begin x.col1:=lx.col1; x.col2:=lx.col2; x.sum:=lx.sum; end else begin x.col1:=lx.col1; x.col2:=rx.col2; x.sum:=lx.sum+rx.sum; if lx.col2=rx.col1 then dec(x.sum); end; end; procedure build(x,l,r:longint);inline; var mid:longint; begin tree2[x].left:=l; tree2[x].right:=r; tree2[x].mark:=-1; if l=r then begin tree1[x].col1:=hash[l]; tree1[x].col2:=hash[l]; tree1[x].sum:=1; exit; end; mid:=(l+r)>>1; build(x<<1,l,mid); build(x<<1+1,mid+1,r); tree1[x]:=tree1[x<<1]+tree1[x<<1+1]; end; procedure maintain(x,y:longint);inline; begin tree2[x].mark:=y; tree1[x].col1:=y; tree1[x].col2:=y; tree1[x].sum:=1; end; procedure pushdown(x:longint);inline; begin if tree2[x].mark<>-1 then begin maintain(x<<1,tree2[x].mark); maintain(x<<1+1,tree2[x].mark); tree2[x].mark:=-1; tree1[x]:=tree1[x<<1]+tree1[x<<1+1]; end; end; procedure change(x,ll,rr,zz:longint);inline; var mid:longint; begin if (tree2[x].left=ll) and (tree2[x].right=rr) then begin maintain(x,zz); exit; end; pushdown(x); mid:=(tree2[x].left+tree2[x].right)>>1; if ll>mid then change(x<<1+1,ll,rr,zz) else if rr<=mid then change(x<<1,ll,rr,zz) else begin change(x<<1,ll,mid,zz); change(x<<1+1,mid+1,rr,zz); end; tree1[x]:=tree1[x<<1]+tree1[x<<1+1]; end; function asksum(x,ll,rr:longint):arr2;inline; var mid:longint; begin pushdown(x); if (tree2[x].left=ll) and (tree2[x].right=rr) then exit(tree1[x]); mid:=(tree2[x].left+tree2[x].right)>>1; if ll>mid then exit(asksum(x<<1+1,ll,rr)) else if rr<=mid then exit(asksum(x<<1,ll,rr)) else exit(asksum(x<<1,ll,mid)+asksum(x<<1+1,mid+1,rr)); end; procedure querysum(x,y:longint);inline; var tmp1,tmp2,tmp:arr2; begin tmp1.sum:=0; tmp2.sum:=0; if dep[x]>dep[y] then swap(x,y); while dep[x]<dep[y] do begin tmp2:=asksum(1,num[top[y]],num[y])+tmp2; y:=fa[top[y]]; end; while top[x]<>top[y] do begin tmp1:=asksum(1,num[top[x]],num[x])+tmp1; x:=fa[top[x]]; tmp2:=asksum(1,num[top[y]],num[y])+tmp2; y:=fa[top[y]]; end; if num[x]<=num[y] then begin swap(tmp1.col1,tmp1.col2); tmp1:=tmp1+asksum(1,num[x],num[y]); tmp1:=tmp1+tmp2; end else begin swap(tmp2.col1,tmp2.col2); tmp:=asksum(1,num[y],num[x]); tmp2:=tmp2+tmp; tmp1:=tmp2+tmp1; end; writeln(tmp1.sum); end; procedure color(x,y,v:longint);inline; begin if dep[x]<dep[y] then swap(x,y); while dep[x]>dep[y] do begin change(1,num[top[x]],num[x],v); x:=fa[top[x]]; end; while top[x]<>top[y] do begin change(1,num[top[x]],num[x],v); change(1,num[top[y]],num[y],v); x:=fa[top[x]]; y:=fa[top[y]]; end; x:=num[x]; y:=num[y]; if x>y then swap(x,y); change(1,x,y,v); end; procedure into;inline; var i,j,k:longint; begin read(n,m); fillchar(tree1,sizeof(tree1),0); fillchar(tree2,sizeof(tree2),0); for i:=1 to n do read(col[i]); total:=0; fillchar(first,sizeof(first),0); for i:=1 to n-1 do begin readln(j,k); addedge(j,k); addedge(k,j); end; fillchar(chose,sizeof(chose),true); dfs(1); fillchar(chose,sizeof(chose),true); make(1,1,1); build(1,1,n) end; procedure work;inline; var j,k,l:longint; ch:char; begin while m>0 do begin dec(m); read(ch); if ch='Q' then begin readln(j,k); querysum(j,k); end else begin readln(j,k,l); color(j,k,l); end; end; end; begin into; work; end.
bz3083遥远的国度
这道题要yy一下。
查询子树很显然想到要dfs序,然后如果root=x就直接找整个树,否则算lca(root,x),如果lca(root,x)不等于x,那么此时x的子树还是原子树(画图yy),否则x原子树中包括了root,那么就反过来,找x除包括root子树外的值,这个值就是root到x的路径的最后一个点(记为j),故区间就是[1,in[j]-1]和[out[j]+1,n]。
type arr1=record toward,next:longint; end; arr2=record left,right,mark:longint; min:int64; end; const maxn=800100; mm=18; var edge:array[0..maxn]of arr1; tree:array[0..maxn]of arr2; first,top,num1,num2,fa,maxson,size,hash,dep,deep,pow,value:array[0..maxn]of longint; chose:array[0..maxn]of boolean; f:array[0..maxn,0..mm]of longint; root,n,m,tot,total:longint; procedure swap(var x,y:longint); var i:longint; begin i:=x; x:=y; y:=i; end; function min(x,y:int64):int64; begin if x<y then exit(x); exit(y); end; procedure addedge(j,k:longint); begin inc(total); edge[total].toward:=k; edge[total].next:=first[j]; first[j]:=total; end; procedure dfs(x:longint); var i,too:longint; begin chose[x]:=false; i:=first[x]; size[x]:=1; maxson[x]:=0; while i<>0 do begin too:=edge[i].toward; if chose[too] then begin deep[too]:=deep[x]+1; fa[too]:=x; dfs(too); inc(size[x],size[too]); if size[maxson[x]]<size[too] then maxson[x]:=too; end; i:=edge[i].next; end; end; procedure make(x,y,depth:longint); var i,too:longint; begin chose[x]:=false; inc(tot); num1[x]:=tot; hash[tot]:=value[x]; top[x]:=y; dep[x]:=depth; if maxson[x]<>0 then make(maxson[x],y,depth); i:=first[x]; while i<>0 do begin too:=edge[i].toward; if chose[too] and (maxson[x]<>too) then make(too,too,depth+1); i:=edge[i].next; end; num2[x]:=tot; end; procedure update(x:longint); begin tree[x].min:=min(tree[x<<1].min,tree[x<<1+1].min); end; procedure maintain(x,y:longint); begin tree[x].min:=y; tree[x].mark:=y; end; procedure pushdown(x:longint); begin if tree[x].mark<>-1 then begin maintain(x<<1,tree[x].mark); maintain(x<<1+1,tree[x].mark); update(x); tree[x].mark:=-1; end; end; procedure build(x,l,r:longint); var mid:longint; begin tree[x].left:=l; tree[x].right:=r; tree[x].mark:=-1; if l=r then begin tree[x].min:=hash[l]; exit; end; tree[x].min:=maxlongint<<2; mid:=(l+r)>>1; build(x<<1,l,mid); build(x<<1+1,mid+1,r); update(x); end; procedure change(x,ll,rr:longint;y:int64); var mid:longint; begin if (tree[x].left=ll) and (tree[x].right=rr) then begin maintain(x,y); exit; end; pushdown(x); mid:=(tree[x].left+tree[x].right)>>1; if ll>mid then change(x<<1+1,ll,rr,y) else if rr<=mid then change(x<<1,ll,rr,y) else begin change(x<<1,ll,mid,y); change(x<<1+1,mid+1,rr,y); end; update(x); end; function askmin(x,ll,rr:longint):int64; var mid:longint; begin if tree[x].left<>tree[x].right then pushdown(x); if (tree[x].left=ll) and (tree[x].right=rr) then exit(tree[x].min); mid:=(tree[x].left+tree[x].right)>>1; if ll>mid then exit(askmin(x<<1+1,ll,rr)) else if rr<=mid then exit(askmin(x<<1,ll,rr)) else exit(min(askmin(x<<1,ll,mid),askmin(x<<1+1,mid+1,rr))); end; procedure color(x,y:longint;v:int64); begin if dep[x]<dep[y] then swap(x,y); while dep[x]>dep[y] do begin change(1,num1[top[x]],num1[x],v); x:=fa[top[x]]; end; while top[x]<>top[y] do begin change(1,num1[top[x]],num1[x],v); change(1,num1[top[y]],num1[y],v); x:=fa[top[x]]; y:=fa[top[y]]; end; x:=num1[x]; y:=num1[y]; if x>y then swap(x,y); change(1,x,y,v); end; procedure atfirst1;//inline; var i,j:longint; begin pow[0]:=1; for i:=1 to mm do pow[i]:=pow[i-1]<<1; for i:=1 to n do f[i,0]:=fa[i]; for i:=1 to mm do for j:=1 to n do f[j,i]:=f[f[j,i-1],i-1]; end; function lca(x,y:longint):longint;//inline; var i:longint; begin if deep[x]<deep[y] then swap(x,y); for i:=mm downto 0 do if deep[x]-pow[i]>=deep[y] then x:=f[x,i]; if x=y then exit(x); for i:=mm downto 0 do if f[x,i]<>f[y,i] then begin x:=f[x,i]; y:=f[y,i]; end; exit(f[x,0]); end; procedure solve(x:longint);//inline; var i,j:longint; ans:int64; begin if x=root then begin writeln(askmin(1,1,n)); exit; end; i:=lca(root,x); if i<>x then writeln(askmin(1,num1[x],num2[x])) else begin j:=root; for i:=mm downto 0 do if deep[f[j,i]]>deep[x] then j:=f[j,i]; ans:=maxlongint<<2; if num1[j]>1 then ans:=min(ans,askmin(1,1,num1[j]-1)); if num2[j]<n then ans:=min(ans,askmin(1,num2[j]+1,n)); writeln(ans); end; end; procedure into; var i,j,k:longint; begin readln(n,m); total:=0; fillchar(first,sizeof(first),0); for i:=1 to n-1 do begin readln(j,k); addedge(j,k); addedge(k,j); end; for i:=1 to n do read(value[i]); readln(root); fillchar(chose,sizeof(chose),true); deep[1]:=1; dfs(1); fillchar(chose,sizeof(chose),true); make(1,1,1); build(1,1,n); atfirst1; end; procedure work;inline; var i,j,k:longint; l:int64; begin for i:=1 to m do begin read(j); case j of 1:readln(root); 2:begin readln(j,k,l); color(j,k,l); end; 3:begin readln(j); solve(j); end; end; end; end; begin into; work; end.