Short But Scary 解题报告

Short But Scary

正解的离线分治+虚树的做法太神奇...搞不到

搞一个菜一点的ddp写写,结果调了200年,下次一定写树剖不写lct了,太难调了...

大概就是按sub2那样维护

你每个重链开一个线段树,然后链头把贡献扔给别的重链,然后每次在链上二分位置查一个和差不多了

然后可以拿lct写

但你得搞清楚翻转的时候要翻转的东西比较多,细节也比较多,异常的难写...

算了懒得说了,给我毒瘤死了...


Code:

#include <cstdio>
#include <cctype>
#include <algorithm>
#define ls ch[now][0]
#define rs ch[now][1]
#define fa par[now]
const int N=1e5+10;
template <class T>
void read(T &x)
{
	x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int n,m;
int ch[N][2],par[N],tag[N];//翻转标记
struct koito_yuu
{
	int siz,is,lef,dat,si;
	//实际大小,子树全是,最左边的点是否是,与父亲关系,虚儿子贡献
}yuu[2][N];
int s[N],tot;
bool isroot(int now){return ch[fa][0]==now||ch[fa][1]==now;}
int identity(int now){return ch[fa][1]==now;}
void connect(int f,int now,int typ){ch[fa=f][typ]=now;}
void Reverse(int now)
{
	tag[now]^=1;
	std::swap(yuu[0][now],yuu[1][now]);
}
void updata(int now)
{
	for(int k=0;k<=1;k++)
	{
		yuu[k][now].is=(yuu[k][ls].is&&yuu[k][now].dat&&yuu[k][rs].is);
		yuu[k][now].siz=yuu[k][ls].siz;
		if(ls)
        {
            yuu[k][now].lef=yuu[k][ls].lef;
            if(yuu[k][ls].is&&yuu[k][now].dat)
            {
                yuu[k][now].siz+=yuu[k][now].si+1;
                if(yuu[k][rs].lef) yuu[k][now].siz+=yuu[k][rs].siz;
            }
		}
		else
        {
            yuu[k][now].lef=yuu[k][now].dat;
            yuu[k][now].siz+=yuu[k][now].si+1;
            if(yuu[k][rs].lef) yuu[k][now].siz+=yuu[k][rs].siz;
        }
	}
}
void pushdown(int now)
{
	if(tag[now])
	{
		if(ls) Reverse(ls);
		if(rs) Reverse(rs);
		tag[now]=0;
	}
}
void Rotate(int now)
{
	int p=fa,typ=identity(now);
	connect(p,ch[now][typ^1],typ);
	if(isroot(p)) connect(par[p],now,identity(p));
	else fa=par[p];
	connect(now,p,typ^1);
	updata(p);
	updata(now);
}
void splay(int now)
{
	while(isroot(now)) s[++tot]=now,now=fa;
	s[++tot]=now;
	while(tot) pushdown(s[tot--]);
	now=s[1];
	for(;isroot(now);Rotate(now))
		if(isroot(fa))
			Rotate(identity(now)^identity(fa)?now:fa);
}
void access(int now)
{
	for(int las=0;now;las=now,now=fa)
	{
		splay(now);
		for(int k=0;k<=1;k++)
		{
			if(yuu[0][rs].lef)
				yuu[k][now].si+=yuu[0][rs].siz;
			if(yuu[0][las].lef)
				yuu[k][now].si-=yuu[0][las].siz;
		}
		rs=las;
		updata(now);
	}
}
void dfs(int now,int f)
{
	yuu[0][now].is=yuu[0][now].lef=yuu[0][now].dat=1;
	//yuu[1][now].is=yuu[1][now].lef=yuu[1][now].dat=1;
	for(int v,i=head[now];i;i=Next[i])
		if((v=to[i])!=f)
			par[v]=now,dfs(v,now),yuu[0][now].si+=yuu[0][v].siz;
	yuu[0][now].siz=yuu[0][now].si+1;
	yuu[1][now].si=yuu[0][now].si;
	yuu[1][now].siz=yuu[0][now].siz;
}
void modi(int u)
{
	access(u);
	splay(u);
	Reverse(u);
}
int query(int now)
{
    pushdown(now);
	if(!rs)
    {
        if(yuu[0][now].dat&&ls) return query(ls)+yuu[0][now].si+1;
        return yuu[0][now].si+1;
    }
	if(yuu[0][rs].is)
	{
		int ret=yuu[0][now].si+1+yuu[0][rs].siz;
		if(yuu[0][now].dat&&now!=1) ret+=query(ls);
		return ret;
	}
	return query(rs);
}
int qry(int u)
{
	access(u);
	splay(u);
	return ((yuu[0][u].dat&&u!=1)?query(ch[u][0]):0)+yuu[0][u].si+1;
}
int main()
{
    freopen("scary.in","r",stdin);
    freopen("scary.out","w",stdout);
	yuu[1][1].dat=yuu[0][0].is=yuu[1][0].is=1;
	read(n),read(m);
	for(int u,v,i=1;i<n;i++) read(u),read(v),add(u,v),add(v,u);
	dfs(1,0);
	for(int op,u,v,i=1;i<=m;i++)
	{
		read(op);
		if(op==1)
		{
			read(u),read(v);
			modi(u),modi(v);
		}
		else
		{
			read(u);
			printf("%d\n",qry(u));
		}
	}
	return 0;
}

2019.3.25

posted @ 2019-03-25 21:58  露迭月  阅读(304)  评论(0编辑  收藏  举报