• 一本通 高手训练 1763 简单树 可持久化线段树 树链刨分 标记永久化


    LINK:简单树

    以后我再不认真读题 我TM活该退役

    又因为没认真读题多调了20min.时间珍贵啊。

    题目最后让ans%n 我没取模 自闭ing.

    还是挺有意思的题目。求x到区间[L,R]的所有点的距离。

    这个还是一个非常经典的问题。需要把答案的式子列出来。

    (sum_{i=L}^R(dis_x+dis_i-dis_{lca(i,x)}))

    前面两项都可以直接计算/预处理得到。

    后面这个东西 看似很难求 考虑 将所有i到根的路径上每一条边赋上权值 然后x向上爬路过的边如果存在权值 那么就是(dis_{lca(i,x)})了。

    这个东西可以利用树链刨分进行快速赋值 而区间问题使用 可持久化线段树即可。

    由于不能下传懒标记 所以需要标记永久化一下。

    const int MAXN=60010;
    int n,m,T,len,id,cnt;
    int root[MAXN];
    int f[MAXN],son[MAXN],dfn[MAXN],top[MAXN],pos[MAXN],d[MAXN],sz[MAXN];
    ll dis[MAXN],sum[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1];
    struct wy
    {
    	int l,r;
    	ll sum;
    	int s;
    }t[MAXN*400];
    inline void add(int x,int y,int z)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    	e[len]=z;
    }
    inline void dfs(int x,int fa)
    {
    	f[x]=fa;d[x]=d[fa]+1;sz[x]=1;
    	go(x)if(tn!=fa)
    	{
    		dis[tn]=dis[x]+e[i];
    		dfs(tn,x);
    		sz[x]+=sz[tn];
    		if(sz[tn]>sz[son[x]])son[x]=tn;
    	}
    }
    inline void dp(int x,int fa)
    {
    	top[x]=fa;dfn[x]=++id;pos[id]=x;
    	if(son[x])dp(son[x],fa);
    	go(x)if(tn!=f[x]&&tn!=son[x])dp(tn,tn);
    }
    inline void insert(int &p,int las,int l,int r,int L,int R)
    {
    	p=++cnt;t[p]=t[las];
    	if(L==l&&R==r){++s(p);return;}
    	sum(p)+=dis[pos[R]]-dis[f[pos[L]]];
    	int mid=(l+r)>>1;
    	if(R<=mid)insert(l(p),l(las),l,mid,L,R);
    	else
    	{
    		if(L>mid)insert(r(p),r(las),mid+1,r,L,R);
    		else insert(l(p),l(las),l,mid,L,mid),insert(r(p),r(las),mid+1,r,mid+1,R);
    	}
    }
    inline ll ask(int p,int las,int l,int r,int L,int R)
    {
    	if(l==L&&R==r)
    	{
    		//cout<<(s(p)-s(las))<<' '<<s(p)<<endl;
    		return sum(p)-sum(las)+(s(p)-s(las))*(dis[pos[R]]-dis[f[pos[L]]]);
    	}
    	int mid=(l+r)>>1;
    	ll cnt=(s(p)-s(las))*(dis[pos[R]]-dis[f[pos[L]]]);
    	if(R<=mid)return cnt+ask(l(p),l(las),l,mid,L,R);
    	if(L>mid)return cnt+ask(r(p),r(las),mid+1,r,L,R);
    	return cnt+ask(l(p),l(las),l,mid,L,mid)+ask(r(p),r(las),mid+1,r,mid+1,R);
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(m);get(T);
    	rep(2,n,i)
    	{
    		int get(x),get(y),get(z);
    		add(x,y,z);add(y,x,z);
    	}
    	dfs(1,0);dp(1,1);
    	rep(1,n,i)sum[i]=sum[i-1]+dis[i];
    	rep(1,n,i)
    	{
    		int x=i;
    		while(top[x]!=1)
    		{
    			insert(root[i],root[i]?root[i]:root[i-1],1,n,dfn[top[x]],dfn[x]);
    			x=f[top[x]];
    		}
    		if(x!=1)insert(root[i],root[i]?root[i]:root[i-1],1,n,dfn[1]+1,dfn[x]);
    	}
    	ll ans=0;
    	rep(1,m,i)
    	{
    		int L,R,x;
    		get(L)^(ans*T);
    		get(R)^(ans*T);
    		get(x)^(ans*T);
    		ans=dis[x]*(R-L+1)+sum[R]-sum[L-1];
    		while(top[x]!=1)
    		{
    			ans-=2*ask(root[R],root[L-1],1,n,dfn[top[x]],dfn[x]);
    			//cout<<ask(root[R],root[L-1],1,n,dfn[top[x]],dfn[x])<<endl;
    			x=f[top[x]];
    		}
    		if(x!=1)ans-=2*ask(root[R],root[L-1],1,n,dfn[1]+1,dfn[x]);
    		putl(ans);ans%=n;
    	}
    	return 0;
    }
    
  • 相关阅读:
    -webkit-margin-before 及 扩展浏览器前缀、内核
    vue封装分页组件
    vue项目中使用qrcode生成二维码
    git中全局设置用户名、邮箱
    promise.all 解说
    超详细弹性盒子布局
    js对象转数组
    js取整数、取余数的方法
    数组方法大全
    Vue绑定class
  • 原文地址:https://www.cnblogs.com/chdy/p/12810906.html
Copyright © 2020-2023  润新知