• HNOI2015 开店


    题目链接在此
    这道题其实有两种做法,动态点分治和树剖+主席树.
    我怕麻烦,写了动态点分治.
    结果还是写了(100+)行...


    考虑这道题怎么做.
    先离散化一下.
    我们先建好点分树,然后用一个(vector)记录这个点在点分树上的子树节点的所有信息.
    这个时空复杂度是(O(n*log n))
    然后我们按每个点的权值排序,每个节点(vector)上的点再记录(3)个信息:子树内所有点的权值排名,子树内所有的点到这个点的距离,子树内所有点到这个点父亲的距离.
    求这个距离和直接暴力算就可以了.
    但是要用(O(1))(lca)

    然后我们做一遍后缀和(为了方便(upper\_bound)(lower\_bound)).
    如何查询呢?
    就直接在点分树上暴力跳父亲.假设询问点是(u),现在的点是(f).那么,(ans+=dis(u,f)*f)中所有不包含(u)的子树(size)(+f)中所有不包含(u)的子树到(f)的距离
    然而,这里所有的东西我们都预处理好了.
    那么,只要拿两个指针二分出子树内点的权值,然后计算即可.
    不要忘记加上(f)的贡献.

    时间复杂度大约是(O(n*log^2n*T))的,其中(T)指大常数.

    我可能语文不太好,可以通过代码理解一下.
    自认为还是比较通俗易懂的.

    下面是又长常数又大的代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #define N (150010)
    #define M (N<<1)
    #define inf (0x7f7f7f7f)
    #define rg register int
    #define Label puts("NAIVE")
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    inline char read(){
    	static const int IN_LEN=1000000;
    	static char buf[IN_LEN],*s,*t;
    	return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
    }
    template<class T>
    inline void read(T &x){
    	static bool iosig;
    	static char c;
    	for(iosig=false,c=read();!isdigit(c);c=read()){
    		if(c=='-')iosig=true;
    		if(c==-1)return;
    	}
    	for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
    	if(iosig)x=-x;
    }
    inline char readchar(){
    	static char c;
    	for(c=read();!isalpha(c);c=read())
    	if(c==-1)return 0;
    	return c;
    }
    const int OUT_LEN = 10000000;
    char obuf[OUT_LEN],*ooh=obuf;
    inline void print(char c) {
    	if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
    	*ooh++=c;
    }
    template<class T>
    inline void print(T x){
    	static int buf[30],cnt;
    	if(x==0)print('0');
    	else{
    		if(x<0)print('-'),x=-x;
    		for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
    		while(cnt)print((char)buf[cnt--]);
    	}
    }
    inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
    struct node{
        int val,id,cnt; LL s,s1;
        friend bool operator <(node a,node b){
            return a.val<b.val;
        }
    };
    typedef vector<node>::iterator iter;
    int n,m,A,ls[N],w[N],f[20][N<<2],dis[N],dfn[N<<2],rdfn[N<<2],ind;
    int fi[N],ne[M],b[M],E,dep[N],c[M],AA;
    int son[N],siz[N],R,root,sum,fa[N],sz[N],lg[N<<2];
    vector<int> nxt[N];
    vector<node> tr[N];
    bool vis[N];
    void add(int x,int y,int z){
        ne[++E]=fi[x],fi[x]=E,b[E]=y,c[E]=z;
    }
    void dfs(int u,int pre){
        rdfn[++ind]=u,dfn[u]=ind;
        for(int i=fi[u];i;i=ne[i]){
            int v=b[i];
            if(v==pre)continue;
            dep[v]=dep[u]+1,dis[v]=dis[u]+c[i],dfs(v,u);
            rdfn[++ind]=u;
        }
    }
    LL getdis(int x,int y){
        if(!x||!y)return 0;
        if(dfn[x]>dfn[y])swap(x,y);
        int k=lg[dfn[y]-dfn[x]+1],ans;
        if(dep[f[k][dfn[x]]]<dep[f[k][dfn[y]-(1<<k)+1]])
        ans=f[k][dfn[x]];
        else ans=f[k][dfn[y]-(1<<k)+1];
        return dis[x]+dis[y]-2*dis[ans];
    }
    void init(){
        dfs(1,0);
        for(int i=1;i<=ind;i++)f[0][i]=rdfn[i];
        for(int i=1;i<=ind;i++)lg[i]=lg[i>>1]+1;
        for(int i=1;i<=19;i++)
        for(int j=1;j+(1<<i)<=ind;j++){
        	if(dep[f[i-1][j]]<dep[f[i-1][j+(1<<(i-1))]])f[i][j]=f[i-1][j];
        	else f[i][j]=f[i-1][j+(1<<(i-1))];
    	}
        
    }
    void find_root(int u,int pre){
        siz[u]=1,son[u]=0;
        for(int i=fi[u];i;i=ne[i]){
            int v=b[i];
            if(vis[v]||v==pre)continue;
            find_root(v,u);
            siz[u]+=siz[v];
            son[u]=max(siz[v],son[u]);
        }
        son[u]=max(son[u],sum-siz[u]);
        if(son[u]<son[root])root=u;
    }
    void solve(int u,int pre){
        fa[u]=pre,vis[u]=1,sz[u]=1;
        tr[u].push_back((node){w[u],u,0,getdis(u,pre),0});
        for(int i=fi[u];i;i=ne[i]){
            int v=b[i];
            if(vis[v])continue;
            root=0,sum=siz[v];
            find_root(v,0);
            nxt[u].push_back(root);
            int tmp=root;
            solve(root,u),sz[u]+=sz[tmp];
            for(int i=0;i<tr[tmp].size()-1;i++)
            tr[u].push_back((node){tr[tmp][i].val,tr[tmp][i].id,0,getdis(tr[tmp][i].id,pre),getdis(tr[tmp][i].id,u)});
        }
        tr[u].push_back((node){A+1,0,1,0,0});
        sort(tr[u].begin(),tr[u].end());
        for(int i=tr[u].size()-2;i>=0;i--)
        tr[u][i].s=tr[u][i+1].s+tr[u][i].s,
        tr[u][i].s1=tr[u][i+1].s1+tr[u][i].s1,
        tr[u][i].cnt=tr[u].size()-i;
    }
    LL query(int l,int r,int st){
        LL ans=0;
        for(int u=st,pre=0;u;pre=u,u=fa[u]){
            if(u==st){
                iter L=lower_bound(tr[u].begin(),tr[u].end(),(node){l,0,0,0,0});
                iter R=upper_bound(tr[u].begin(),tr[u].end(),(node){r,0,0,0,0});
                LL val=L->s1-R->s1;
                ans+=val;continue;
            }
            LL len=getdis(st,u);
            LL sums=0,sumd=0;
            for(int i=0;i<nxt[u].size();i++)
            if(nxt[u][i]!=pre){
                int v=nxt[u][i];
                iter L=lower_bound(tr[v].begin(),tr[v].end(),(node){l,0,0,0,0});
                iter R=upper_bound(tr[v].begin(),tr[v].end(),(node){r,0,0,0,0});
                sums+=L->cnt-R->cnt,sumd+=L->s-R->s;
            }
            if(w[u]<=r&&w[u]>=l)ans+=len;
            ans+=len*sums+sumd;
        }
        return ans;
    }
    int main(){
        read(n),read(m),read(AA),lg[0]=-1;
        for(int i=1;i<=n;i++)read(w[i]),ls[i]=w[i];
        sort(ls+1,ls+n+1),A=unique(ls+1,ls+n+1)-ls-1;
        for(int i=1;i<=n;i++)w[i]=lower_bound(ls+1,ls+A+1,w[i])-ls;
        for(int i=1;i<n;i++){
            int x,y,z;
            read(x),read(y),read(z);
            add(x,y,z),add(y,x,z);
        }
        init(),sum=n,son[0]=n+1,root=0;
        find_root(1,0),R=root,find_root(R,0);
        solve(root,0);
        LL lans=0;
        while(m--){
            int l,r,x;
            read(x),read(l),read(r);
            l=(l+lans)%AA,r=(r+lans)%AA;
            if(l>r)swap(l,r);
            l=lower_bound(ls+1,ls+A+1,l)-ls;
            r=upper_bound(ls+1,ls+A+1,r)-ls-1;
            printf("%lld
    ",lans=query(l,r,x));
        }
    }
    
  • 相关阅读:
    委托示例一则
    JQuery学习笔记(3)JQuery中的DOM操作
    JQuery学习笔记(2)JQuery选择器
    把.net的web开发补起来,徐图之
    今天把swagger补了一下
    Azure Cosmos DB Core (SQL)
    wcf callback channel问题多多
    gitlab安装
    Kubernetes
    搜索功能实现
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10141161.html
Copyright © 2020-2023  润新知