zoukankan      html  css  js  c++  java
  • 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));
        }
    }
    
  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10141161.html
Copyright © 2011-2022 走看看