HDU

来源:互联网 发布:淘宝店铺首页1200 编辑:程序博客网 时间:2024/06/13 05:52

HDU - 5840 - This world need more Zhu

将询问分为 k 大和 k 小的两部分。假设kB 的部分为 k 小。
对于 k 大的情况,我们考虑直接暴力。把每一条边分成向上和向下的两条边:
对于向上的边,开始点 (d[x]d[u]+1)%k==0 。故 d[x]=d[u]k+1
对于向下的边,开始点 (d[x]d[lca]+1+d[u]d[lca])%k==0d[x]=d[lca]+(d[lca]d[u]1)%k
可以直接从开始点向上/向下走,每次询问复杂度为 O(nB)
对于 k 小的情况,我们考虑使用树剖。
对于一条链 (u,v)
对于向上的边 x 被计数当且仅当 (d[u]d[x]+1)%k==0 。故 d[x]=(d[u]+1)%k
对于向下的边 x 被计数当且仅当 (d[x]d[lca]+d[u]d[lca]+1)%k==0 。故d[x]=(2×d[lca]d[u]1)%k
对于每一个 k 。可以考虑将树上所有点根据第一关键字 d[i]%k 升序,第二关键字树剖 dfs 序升序来排序,放到线段树上。这样对于一个询问,我们只需要访问一条链上模 k 值给定的一段就行。对于每条重链,要访问的一段应该是连续的,因为重链的 dfs 序连续。一次询问复杂度是 O(log2n)
因此总的复杂度是 O(QlargenB+n+Bn+Qsmalllog2n)
B100 。这样总复杂度可以到 108 左右。

#include<bits/stdc++.h>#define lson (rt<<1)#define rson (rt<<1|1)using namespace std;const int N=1e5+7;const int BLOCK=100;int n,a[N],ans[N],son[N],fa[N],top[N],sz[N],id[N],d[N],b[N],cnt,st[N],tp,mx[N<<2],L[BLOCK],R[BLOCK],tmp[N];vector<int> hs[BLOCK],adj[N];struct Query{    int u,v,k,down,lca,id;};vector<Query> q1[N],q2[BLOCK];inline int LCA(int u,int v){    while(top[u]!=top[v])    {        if(d[top[u]]<d[top[v]]) swap(u,v);        u=top[u];        u=fa[u];    }    return d[u]<d[v]?u:v;}inline void init(){    memset(a,0,sizeof(a));    memset(ans,0,sizeof(ans));    top[1]=1;    tp=cnt=0;    memset(son,-1,sizeof(son));    for(int i=1;i<=n;++i) q1[i].clear(),adj[i].clear();    for(int i=0;i<BLOCK;++i) q2[i].clear();}void dfs1(int u,int deep,int father){    sz[u]=1;d[u]=deep;fa[u]=father;    for(int v : adj[u])    {        if(v==father) continue;        dfs1(v,deep+1,u);        sz[u]+=sz[v];        if(son[u]==-1||sz[v]>sz[son[u]])            son[u]=v;    }}void dfs2(int u){    id[u]=++cnt;    b[cnt]=u;    if(son[u]!=-1)    {        top[son[u]]=top[u];        dfs2(son[u]);    }    for(int v : adj[u])    {        if(v==fa[u]||v==son[u]) continue;        top[v]=v;        dfs2(v);    }}void work_1(int u){    st[tp++]=u;    for(Query & q : q1[u])    {        int u=q.u,v=q.v,lca=q.lca,k=q.k,id=q.id,down=q.down;        if(down)        {            int tmp=d[lca]+((d[lca]-d[u]-1)%k+k)%k;            while(tmp<tp&&d[st[tmp]]<=d[v]) ans[id]=max(ans[id],a[st[tmp]]),tmp+=k;        }        else        {            int tmp=tp-k;            while(tmp>=0&&d[st[tmp]]>=d[lca]) ans[id]=max(ans[id],a[st[tmp]]),tmp-=k;        }    }    for(int v : adj[u])    {        if(v==fa[u]) continue;        work_1(v);    }    --tp;}inline void push_up(int rt){    mx[rt]=max(mx[lson],mx[rson]);}void build(int rt,int l,int r){    if(l==r)  { mx[rt]=a[b[tmp[l]]];return ; }    int m=(l+r)>>1;    build(lson,l,m);    build(rson,m+1,r);    push_up(rt);}int query(int rt,int l,int r,int ql,int qr){    if(ql<=l&&qr>=r) return mx[rt];    int m=(l+r)>>1;    int res=0;    if(ql<=m) res=max(res,query(lson,l,m,ql,qr));    if(qr>m) res=max(res,query(rson,m+1,r,ql,qr));    return res;}inline int cal(int l,int r,int k){    l=lower_bound(tmp+L[k],tmp+R[k]+1,l)-tmp;    r=upper_bound(tmp+L[k],tmp+R[k]+1,r)-tmp-1;    return l<=r?query(1,1,n,l,r):0;}inline void solve(int x,int u,int k,int id){    if(d[u]<d[x]) return ;    while(top[u]!=top[x])    {        ans[id]=max(ans[id],cal(::id[top[u]],::id[u],k));        u=fa[top[u]];    }    ans[id]=max(ans[id],cal(::id[x],::id[u],k));}inline void work_2(int k){    for(int i=0;i<k;++i) hs[i].clear();    for(int i=1;i<=n;++i) hs[d[b[i]]%k].push_back(i);    int tot=0;    for(int i=0;i<k;++i)    {        L[i]=tot+1;        for(int v : hs[i]) tmp[++tot]=v;        R[i]=tot;    }    build(1,1,n);    for(Query & q : q2[k])    {        int u=q.u,v=q.v,k=q.k,lca=q.lca,id=q.id;        solve(lca,u,(d[u]+1)%k,id);        solve(lca,v,((2*d[lca]-d[u]-1)%k+k)%k,id);    }}int main(){    int T,m;    scanf("%d",&T);    for(int kase=1;kase<=T;++kase)    {        scanf("%d%d",&n,&m);        init();        for(int i=1;i<=n;++i) scanf("%d",&a[i]);        for(int i=1;i<n;++i)        {            int u,v;            scanf("%d%d",&u,&v);            adj[u].push_back(v);            adj[v].push_back(u);        }        dfs1(1,0,1);        dfs2(1);        for(int i=0;i<m;++i)        {            int u,v,k;            scanf("%d%d%d",&u,&v,&k);            if(k<BLOCK) q2[k].push_back({u,v,k,1,LCA(u,v),i});            else            {                q1[u].push_back({u,v,k,0,LCA(u,v),i});                q1[v].push_back({u,v,k,1,LCA(u,v),i});            }        }        work_1(1);        for(int i=0;i<BLOCK;++i) if(q2[i].size()) work_2(i);        printf("Case #%d:\n",kase);        for(int i=0;i<m;++i)            printf("%d\n",ans[i]);    }    return 0;}