【[SDOI2014]旅行】树链剖分+动态开点
最近学了树链剖分,又可以做好多好多难题水题真是恶心开心!!!
luogu上的主席树标签迷惑了我好久,,,结果好像只用到了主席树的思想,主席树的操作根本没有....
没有宗教的限制,这道题就是树剖的SUM和MAX操作。但是,也很容易想到,对于每一个宗教就建一颗树,于是就可以每次都能够进行查询每个宗教的东西了。很明显,空间爆炸呀,动态开点就来咯!这里用到一个主席树思想就是每一个宗教建一颗树,可能也算是勉强有主席树元素吧。
注意一些小操作-》如果某个点改宗教,原宗教线段树里直接改成0,然后记录下w,返回到新的宗教线段树里就可以了
以及!!!修改原来的宗教数组(也只有菜鸡如我才会搞忘),恩,数组开大一点。
认真写,没有写出小bug这道题还是挺简单的,树剖板子题一道,写出bug,呵呵,慢慢调吧。
#include<cstdio>
#include<algorithm>
#define midd ((l+r)>>1)
using namespace std;
const int maxn=100005;
int n,q;
int oldw[maxn],oldc[maxn];
int la[maxn<<1],nt[maxn<<1],en[maxn<<1],owo;
inline void addedge(int a,int b)
{en[++owo]=b; nt[owo]=la[a]; la[a]=owo;}
//
int size[maxn],dep[maxn],zerz[maxn],top[maxn],newid[maxn],fa[maxn],oldid[maxn],idcnt;
void fzb(int x,int ba)
{
dep[x]=dep[ba]+1;
int maxsize=0; size[x]=1; zerz[x]=0;
for(int it=la[x];it;it=nt[it])
{
if(en[it]==ba) continue;
fa[en[it]]=x;
fzb(en[it],x);
size[x]+=size[en[it]];
if(size[en[it]]>maxsize)
{
maxsize=size[en[it]];
zerz[x]=en[it];
}
}
}
void lzb(int x,int ace)
{
newid[x]=++idcnt; top[x]=ace;
if(zerz[x]) lzb(zerz[x],ace);
for(int it=la[x];it;it=nt[it])
{
if(en[it]==fa[x]||en[it]==zerz[x]) continue;
lzb(en[it],en[it]);
}
}
//
int tot,rt[maxn];
struct node
{
int sumw,maxw,ls,rs;
}z[maxn<<5];
inline void putup(int p)
{
z[p].maxw=max(z[z[p].ls].maxw,z[z[p].rs].maxw);
z[p].sumw=z[z[p].ls].sumw+z[z[p].rs].sumw;
}
void ins(int &p,int oid,int ww,int l,int r)
{
if(!p) p=++tot;
if(l==r) { z[p].sumw=z[p].maxw=ww; return; }
if(oid<=midd) ins(z[p].ls,oid,ww,l,midd);
else ins(z[p].rs,oid,ww,midd+1,r);
putup(p);
}
void del(int &p,int oid,int &ww,int l,int r)
{
if(!p) p=++tot;
if(l==r) { ww=z[p].sumw; z[p].sumw=z[p].maxw=0; return; }
if(oid<=midd) del(z[p].ls,oid,ww,l,midd);
else del(z[p].rs,oid,ww,midd+1,r);
putup(p);
}
int qsum(int &p,int x,int y,int l,int r)
{
if(!p) p=++tot;
if(x<=l&&r<=y) return z[p].sumw;
int sss=0;
if(x<=midd&&y>=l) sss+=qsum(z[p].ls,x,y,l,midd);
if(x<=r&&y>midd) sss+=qsum(z[p].rs,x,y,midd+1,r);
return sss;
}
int qmax(int &p,int x,int y,int l,int r)
{
if(!p) p=++tot;
if(x<=l&&r<=y) return z[p].maxw;
int sss=0;
if(x<=midd&&y>=l) sss=max(sss,qmax(z[p].ls,x,y,l,midd));
if(x<=r&&y>midd) sss=max(sss,qmax(z[p].rs,x,y,midd+1,r));
return sss;
}
//
int querysum(int cc,int x,int y)
{
int sss=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
sss+=qsum(rt[cc],newid[top[x]],newid[x],1,n);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
sss+=qsum(rt[cc],newid[x],newid[y],1,n);
return sss;
}
int querymax(int cc,int x,int y)
{
int sss=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
sss=max(sss,qmax(rt[cc],newid[top[x]],newid[x],1,n));
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
sss=max(sss,qmax(rt[cc],newid[x],newid[y],1,n));
return sss;
}
//
void main_main()
{
int a,b,aha;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) { scanf("%d%d",&oldw[i],&oldc[i]); }
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&a,&b);
addedge(a,b); addedge(b,a);
}
fzb(1,0); lzb(1,1);
for(int i=1;i<=n;i++)
ins(rt[oldc[i]],newid[i],oldw[i],1,n);
char ss[3];
while(q--)
{
scanf("%s%d%d",ss,&a,&b);
if(ss[1]=='S')
{
printf("%d\n",querysum(oldc[a],a,b));
}
else if(ss[1]=='C')
{
del(rt[oldc[a]],newid[a],aha,1,n);
ins(rt[b],newid[a],aha,1,n);
oldc[a]=b;
}
else if(ss[1]=='W')
{
ins(rt[oldc[a]],newid[a],b,1,n);
}
else if(ss[1]=='M')
{
printf("%d\n",querymax(oldc[a],a,b));
}
}
}
const int main_stack=16;
char my_stack[128<<20];
int main() {
__asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");
__asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp");
main_main();
__asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");
return 0;
}
这里的扩栈操作是因为NKOJ会栈内存不够。。。
少有的一道一个小时就搞出来了的数据结构题。。。

浙公网安备 33010602011771号