zoukankan      html  css  js  c++  java
  • [HNOI2015]开店

    题面在这里

    题意

    一棵(n)个节点的树,树上每个节点有一个权值(v[i]),边有边权(w[e]),
    给出(Q)次询问,对于每次询问((u,L,R)),求点权在([L,R])的点到(u)的路径长度之和
    强制在线~

    数据范围

    [nle1.5 imes10^5,Qle2 imes10^5,A<=10^9 ]

    sol

    不考虑点权,如果仅求所有点到(u)的距离该怎么做?
    (ecausesum_{v=1}^{n}dist(u,v)=sum_{v=1}^{n}dep[v]+n imes dep[u]-2 imessum_{v=1}^{n}dep[lca(u,v)]),
    (sum_{v=1}^{n}dep[v]),(n imes dep[u])都可以利用前缀和求出;
    瓶颈在于求(sum_{v=1}^{n}dep[lca(u,v)]);
    如何求?首先将所有节点进行路径覆盖((v,rt)),
    最后答案即为(u)(rt)的路径(()边权( imes)覆盖次数())之和
    这个可以使用树链剖分做
    当有点权([L,R])的限制的时候离散化+主席树做前缀和即可
    时间和空间应该都是(O(nlog^2n))的...

    线段树标记永久化

    第一次写居然是在主席树上...
    主要思想是修改时直接在对应的节点打(lazy),询问时直接把标记往下带
    具体实现:

    修改

    假设我们现在打了一个(modify(l,r,x,y))函数,
    询问区间为([x,y]),目前线段树的区间为([l,r]);
    当到达底部((xle l && r le y))的时候,我们直接打(lazy)(不需要加(sum))就可以了
    回溯上来的时候,由于(lazy)节点的祖先节点在询问时访问不到这个(lazy),
    我们就需要把打了这个(lazy)后对祖先节点的影响直接加到祖先节点上

    如果我们需要支持区间加,像这样

    #define ls (i<<1)
    #define rs (i<<1|1)
    #define mid ((l+r)>>1)
    int sum[N<<4],lazy[N<<4];
    void modify(int i,int l,int r,int x,int y,int add){
        //这个是线段树版本,主席树的下面有
        if(x<=l&&r<=y){lazy[i]+=add;return;}
        sum[i]+=add*(y-x+1);
        if(y<=mid)modify(ls,l,mid,x,y,add);
        else if(x>mid)modify(rs,mid+1,r,x,y,add);
        else modify(ls,l,mid,x,mid,add),modify(rs,mid+1,r,mid+1,y,add);
    }
    

    询问

    知道(lazy)标记是怎么来的就好办了,
    我们知道此时一个线段树节点的(lazy)标记是其所有祖先(lazy)标记的总和,
    于是一路下来加好(lazy),当到达底部((xle l && r le y))的时候,
    把之前所有(lazy)的和( imes)底部节点的权值就可以了

    如果我们需要支持区间求和(爆精度什么的我才不管呢),像这样

    #define ls (i<<1)
    #define rs (i<<1|1)
    #define mid ((l+r)>>1)
    int sum[N<<4],lazy[N<<4];
    int query(int i,int l,int r,int x,int y){
        //这个是线段树版本,主席树的下面有
        RG int ret=sum[i];
        if(x<=l&&r<=y)return ret+lz[i]*(y-x+1);
        if(y<=mid)return ret+query(ls,l,mid,x,y);
        else if(x>mid)return ret+query(rs,mid+1,r,x,y);
        else return ret+query(ls,l,mid,x,mid)+query(rs,mid+1,r,mid+1,y);
    }
    

    代码

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define mp make_pair
    #define pub push_back
    #define puf push_front
    #define pob pop_back
    #define pof pop_front
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const dd eps=1e-10;
    const int mod=1e8;
    const int N=150010;
    const int M=150*N;
    il ll read(){
    	RG ll data=0,w=1;RG char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    	return data*w;
    }
    
    il void file(){
    	freopen("shop10.in","r",stdin);
    	freopen("a.out","w",stdout);
    }
    
    struct node{
    	int x,y;
    	bool operator <(const node b)const{
    		if(x==b.x)return y<b.y;
    		return x<b.x;
    	}
    }a[N];
    int head[N],nxt[N<<1],to[N<<1],val[N<<1],cnte;
    ll sumE[N];
    il void add(int u,int v,int w){
    	to[++cnte]=v;
    	nxt[cnte]=head[u];
    	val[cnte]=w;
    	head[u]=cnte;
    }
    int n,Q,A,rt[N],cnt;
    struct tree{int ls,rs,tag;ll sum;}t[M];
    
    int fa[N],sz[N],son[N];ll dep[N];
    void dfs1(int u,int f){
    	fa[u]=f;sz[u]=1;
    	for(RG int i=head[u];i;i=nxt[i]){
    		RG int v=to[i];if(v==fa[u])continue;
    		dep[v]=dep[u]+val[i];dfs1(v,u);
    		sz[u]+=sz[v];if(sz[v]>sz[son[u]])son[u]=v;
    	}
    }
    
    int dfn[N],top[N];
    void dfs2(int u,int tp){
    	top[u]=tp;dfn[u]=++cnt;
    	sumE[cnt]=dep[u]-dep[fa[u]];
    	if(son[u])dfs2(son[u],tp);
    	for(RG int i=head[u];i;i=nxt[i]){
    		RG int v=to[i];if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    
    #define mid ((l+r)>>1)
    void build(int &i,int l,int r){
    	i=++cnt;if(l==r)return;
    	build(t[i].ls,l,mid);build(t[i].rs,mid+1,r);
    }
    
    void modify(int &i,int l,int r,int x,int y){
    	t[++cnt]=t[i];i=cnt;
    	if(l==x&&r==y){t[i].tag++;return;}
    	t[i].sum+=sumE[y]-sumE[x-1];
    	if(y<=mid)modify(t[i].ls,l,mid,x,y);
    	else if(x>mid)modify(t[i].rs,mid+1,r,x,y);
    	else modify(t[i].ls,l,mid,x,mid),modify(t[i].rs,mid+1,r,mid+1,y);
    }
    
    ll query(int &i,int l,int r,int x,int y){
    	RG ll ret=1ll*t[i].tag*(sumE[y]-sumE[x-1]);
    	if(l==x&&r==y)return ret+t[i].sum;
    	if(y<=mid)return ret+query(t[i].ls,l,mid,x,y);
    	else if(x>mid)return ret+query(t[i].rs,mid+1,r,x,y);
    	else return ret+query(t[i].ls,l,mid,x,mid)+query(t[i].rs,mid+1,r,mid+1,y);
    }
    
    ll sumdis[N],ans;
    il ll ask(int k,int u){
    	ll ret=0;
    	while(top[u]^1)
    		ret+=query(rt[k],1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
    	ret+=query(rt[k],1,n,1,dfn[u]);return ret;
    }
    
    int main()
    {
    	n=read();Q=read();A=read();
    	for(RG int i=1;i<=n;i++)a[i]=(node){read(),i};
    	sort(a+1,a+n+1);
    	for(RG int i=1,aa,b,c;i<n;i++){
    		aa=read();b=read();c=read();
    		add(aa,b,c);add(b,aa,c);
    	}
    	dfs1(1,0);dfs2(1,1);cnt=0;build(rt[0],1,n);
    	for(RG int i=1;i<=n;i++)
    		sumE[i]+=sumE[i-1],sumdis[i]+=sumdis[i-1]+dep[a[i].y];
    	for(RG int i=1;i<=n;i++){
    		RG int u=a[i].y;rt[i]=rt[i-1];
    		while(top[u]^1)modify(rt[i],1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];
    		modify(rt[i],1,n,1,dfn[u]);
    	}
    	for(RG int i=1,u,l,r;i<=Q;i++){
    		u=read();l=(read()+ans)%A;r=(read()+ans)%A;
    		if(l>r)swap(l,r);
    		l=lower_bound(a+1,a+n+1,(node){l,0})-a;
    		r=upper_bound(a+1,a+n+1,(node){r,n})-a-1;
    		printf("%lld
    ",ans=dep[u]*(r-l+1)+sumdis[r]-sumdis[l-1]-2*(ask(r,u)-ask(l-1,u)));
    	}
    	return 0;
    }
    
    

    zsy大佬是最强的!!!

  • 相关阅读:
    JavaEE开发中系列总结
    equals及==问题
    eclipse debug弹出窗
    MacOS Sierra 显示隐藏文件命令
    了解点Excel VBA 代码,让工作效率提升多倍~
    PADS Layout进行eco对比更新
    PCB走线规则与一些技巧介绍
    旁路电容与去耦电容的区别
    Flash download failed-Cortex-M3的原因及解决办法
    Keil U5不能识别DAP仿真器的解决办法及原因
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8709155.html
Copyright © 2011-2022 走看看