【[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会栈内存不够。。。

少有的一道一个小时就搞出来了的数据结构题。。。

posted @ 2018-03-24 19:34  Newuser233  阅读(4)  评论(0)    收藏  举报