zoukankan      html  css  js  c++  java
  • bzoj3626[LNOI2014]LCA

    传送门

    思维题吧,神奇的模型转化,除了模型转化别的都是板子
    最最最暴力的想法当然是一个一个去求lca啊,然后恭喜你获得了0分的好成绩
    其实可以考虑另一种暴力,dep(lca(i,z))也可以看做是i点和z点到根节点路径上公共的路径的长度,那么我们就可以得到一个做法,将z到根的路径上每个节点都加上1的权值,然后对于[l,r]之间的点一一去求到根节点路径的权值和,这样依然没有分,但是这个思路很优秀。
    我们发现这个做法是可逆的,所以我们可以将l~r间的点到根的路径上的点权值都加1,对于z求到根的权值和与之前的做法是等价的。
    然后发现在线做很多路径都被重复加入和删除,所以考虑离线。
    在统计答案时再用差分的思想将[l,r]处理成[1,r]-[1,l-1],就可以排序后保证每个点到根的路径只被插入一次了。
    路径处理自然是树链剖分啦
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=5e4+1,mod=201314;
    int dep[maxn],top[maxn],tot,now,id[maxn],size[maxn],n,q,cnt,num,pre[maxn*2],nxt[maxn*2],h[maxn],f[maxn],ans[maxn],w;
    struct oo{int x,y,id;}a[maxn*2];
    struct segment_tree{int l,r,tag,sum;}s[maxn*4];
    void add(int x,int y)
    {
    	pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,
    	pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt;
    }
    bool cmp(oo a,oo b){return a.x<b.x;}
    void dfs(int x,int fa)
    {
    	size[x]=1;
    	for(rg int i=h[x];i;i=nxt[i])
    		if(pre[i]!=fa)dep[pre[i]]=dep[x]+1,dfs(pre[i],x),size[x]+=size[pre[i]];
    }
    void dfs1(int x,int fa)
    {
    	top[x]=fa,id[x]=++tot;int k=0;
    	for(rg int i=h[x];i;i=nxt[i])
    		if(dep[pre[i]]>dep[x]&&size[pre[i]]>size[k])k=pre[i];
    	if(!k)return ;dfs1(k,fa);
    	for(rg int i=h[x];i;i=nxt[i])
    		if(dep[pre[i]]>dep[x]&&pre[i]!=k)dfs1(pre[i],pre[i]);
    }
    void build(int x,int l,int r)
    {
    	s[x].l=l,s[x].r=r;
    	if(l==r)return ;
    	int mid=(l+r)>>1;
    	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
    }
    void update(int x){s[x].sum=(s[x<<1].sum+s[x<<1|1].sum)%mod;}
    void pushdown(int x)
    {
    	int ls=x<<1,rs=x<<1|1;
    	s[ls].tag+=s[x].tag,s[rs].tag+=s[x].tag;
    	(s[ls].sum+=s[x].tag*(s[ls].r-s[ls].l+1))%=mod,
    	(s[rs].sum+=s[x].tag*(s[rs].r-s[rs].l+1))%=mod;
    	s[x].tag=0;
    }
    void change(int x,int l,int r)
    {
    	if(l<=s[x].l&&r>=s[x].r)
    	{
    		(s[x].sum+=(s[x].r-s[x].l+1))%=mod,s[x].tag++;
    		return ;
    	}
    	if(s[x].tag)pushdown(x);
    	int mid=(s[x].l+s[x].r)>>1;
    	if(l<=mid)change(x<<1,l,r);
    	if(r>mid)change(x<<1|1,l,r);
    	update(x);
    }
    void modify(int x,int y)
    {
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		change(1,id[top[x]],id[x]);x=f[top[x]];
    	}
    	if(id[x]>id[y])swap(x,y);
    	change(1,id[x],id[y]);
    }
    void get(int x,int l,int r)
    {
    	if(l<=s[x].l&&r>=s[x].r)
    	{
    		(w+=s[x].sum)%=mod;
    		return ;
    	}
    	if(s[x].tag)pushdown(x);
    	int mid=(s[x].l+s[x].r)>>1;
    	if(l<=mid)get(x<<1,l,r);
    	if(r>mid)get(x<<1|1,l,r);
    	update(x);
    }
    int qsum(int x,int y)
    {
    	w=0;
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]])swap(x,y);
    		get(1,id[top[x]],id[x]);x=f[top[x]];
    	}
    	if(id[x]>id[y])swap(x,y);
    	get(1,id[x],id[y]);return w;
    }
    int main()
    {
    	read(n),read(q);
    	for(rg int i=2;i<=n;i++)read(f[i]),f[i]++,add(i,f[i]);
    	dfs(1,0),dfs1(1,1),build(1,1,tot);
    	for(rg int i=1,x,y,z;i<=q;i++)
    	{
    		read(x),read(y),read(z),x++,y++,z++;
    		a[++num].x=x-1,a[num].y=z,a[num].id=-i,a[++num].x=y,a[num].y=z,a[num].id=i;
    	}
    	sort(a+1,a+num+1,cmp);
    	for(rg int i=1;i<=num;i++)
    	{
    		while(now<a[i].x)modify(++now,1);
    		if(a[i].id<0)ans[-a[i].id]=qsum(a[i].y,1);
    		else ans[a[i].id]=(qsum(a[i].y,1)-ans[a[i].id]+mod)%mod;
    	}
    	for(rg int i=1;i<=q;i++)printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    学习subprocess模块...
    【排列组合】
    【约瑟夫问题】
    【craps赌博游戏】
    【洗扑克牌(乱数排列)】
    【最大访客数】
    【后序式的运算】
    【中序式转后序式】
    【python基础】之元组 集合 字典
    【费式数列(Fibonacci数列)】
  • 原文地址:https://www.cnblogs.com/lcxer/p/10225216.html
Copyright © 2011-2022 走看看