【解不出来】【莫队】【多校】This world need more Zhu HDU5799

(弄了一个月的搬瓦工搭个梯子顺便搭个博客玩……不务正业)


题目描述

As we all know, Zhu is the most powerful man. He has the infinite power to protest the world. We need more men like Zhu!
In Duoladuo, this place is like a tree. There are n points and n1 edges. And the root is 1 . Each point can reach other points. Each point has a value a[i] named Zhu power.
Liao is a curious baby, he has m questions to ask Zhu. But now Zhu is busy, he wants you to help him answer Liao’s questions.
Liao’s question will be like op u v a b.
if op is 1, the u is equal to v . Liao wants to know the gcd of the sum of numbers thats appears a times and the sum of numbers that appears b times in subtree u .
if op is 2, Liao wants to know the gcd of the sum of numbers thats appears a times and the sum of numbers that appears b times on the path from u to v.
gcd is greatest common divisor.
notice: we can know gcd(x,0)=x .

输入

In the first line contains a single positive integer T , indicating number of test case.
In the second line there are two numbers n,m. n is the size of Duoladuo. m is the number of Liao’s questions.
The next line contains n integers A1,A2,AN, means the value of i point.
In the next n1 line contains tow numbers u,v . It means there is a edge between point u and point v.
The next m lines will be the Liao’s question:
1 u v a b
2 u v a b
1T10,1n100000,1m100000,1op2,1u,vn,1a,bn,1Ai1000000000.

输出

For each case, output Case #i:. ( i is the number of the test case, from 1 to T ).
Then, you need to output the answer for every Liao’s questions.

样例输入

1
5 5
1 2 4 1 2
1 2
2 3
3 4
4 5
1 1 1 1 1
1 1 1 1 2
2 1 5 1 1
2 1 5 1 2
2 1 1 2 2

样例输出

Case #1:
4
1
4
1
0

对于操作1只要搞出来树的dfs序,每个询问对应一个连续区间,直接做序列莫队即可。
对于操作2就是树上莫队。
然后我按照之前的做法在搞出的括号序上跑莫队,T了。Baidu到一篇博客也说本地测10s,根本卡不过去。看了一下数据,后面五个点的莫队基本上都跑满了nn。本来 n <script type="math/tex" id="MathJax-Element-36">n</script>给的范围就很大了,然后对于这种专门构造数据卡某种算法的我也是无Fuck说。那种树分块的暂时还不会,以后学一下。
另外那篇博客说做两次常数大其实不然,想一下也是分开做复杂度更优。
下面就贴个一起做的代码吧,写的还算比较短,不过很丑也过不去就是了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
struct rec{
    int id, col;
}arr[100010];
struct que{
    int x, y, l, r, lca, a, b, id; long long ans;
};
int T, n, m, to[100010];
inline int rd(){
    int a=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) (a*=10)+=c-'0', c=getchar();
    return a;
}
// 离散化
void lis(){
    sort(arr+1, arr+n+1, [](rec a, rec b){return a.col<b.col;});
    int t=1;
    for(int i=1;i<=n;){
        int p=arr[i].col; to[t]=p;
        while(i<=n&&arr[i].col==p) arr[i++].col=t;
        t++;
    }
    sort(arr+1, arr+n+1, [](rec a, rec b){return a.id<b.id;});
}
long long gcd(long long a, long long b){
    if(!a) return b;
    while(b)
        a%=b, swap(a, b);
    return a;
}
// 莫队
namespace mo{
    que qs[100010];
    int seq[200010], op[100010], ed[100010], ed2[100010], T, qpt, bk, bel[200010];
    int cnt[100010], cnt2[100010]; long long sum[100010], sum2[100010];
    bool ext[100010], u[200010];
    void init(){
        T=qpt=0;
        memset(cnt, 0, sizeof cnt); memset(sum, 0, sizeof sum);
        memset(cnt2, 0, sizeof cnt2); memset(sum2, 0, sizeof sum2);
        memset(ext, 0, sizeof ext); memset(u, 0, sizeof u);
    }
    // 处理询问
    void prework(){
        bk=ceil(sqrt(T));
        for(int i=0, t=0;i<T;i+=bk, t++)
            for(int j=0;i+j<T&&j<bk;j++)
                bel[i+j]=t;
        for(int i=0;i<qpt;i++){
            if(qs[i].lca){
                if(qs[i].x==qs[i].y){
                    if(qs[i].a==1||qs[i].b==1) qs[i].ans=to[arr[qs[i].x].col];
                    else qs[i].ans=0;
                    continue;
                }
                if(op[qs[i].x]>op[qs[i].y]) swap(qs[i].x, qs[i].y);
                if(qs[i].x==qs[i].lca) qs[i].l=op[qs[i].x]+1;
                else qs[i].l=ed[qs[i].x];
                qs[i].r=op[qs[i].y];
            }
            else
                qs[i].l=op[qs[i].x], qs[i].r=ed[qs[i].x];
        }
    }
    void inc(int ss){
        if(!u[ss]) return; int p=seq[ss];
        sum2[cnt2[arr[p].col]++]-=to[arr[p].col];
        sum2[cnt2[arr[p].col]]+=to[arr[p].col];
    }
    void dec(int ss){
        if(!u[ss]) return; int p=seq[ss];
        sum2[cnt2[arr[p].col]--]-=to[arr[p].col];
        sum2[cnt2[arr[p].col]]+=to[arr[p].col];
    }
    void tog(int p){
        if(ext[p]) sum[cnt[arr[p].col]--]-=to[arr[p].col], sum[cnt[arr[p].col]]+=to[arr[p].col];
        else sum[cnt[arr[p].col]++]-=to[arr[p].col], sum[cnt[arr[p].col]]+=to[arr[p].col];
        ext[p]^=1;
    }
    void go(){
        prework();
        sort(qs, qs+qpt, [](que a, que b){return bel[a.l]==bel[b.l]?a.r<b.r:bel[a.l]<bel[b.l];});
        int l=0, r=0; ext[1]=1; sum[1]=sum2[1]=to[arr[1].col]; cnt[arr[1].col]=cnt2[arr[1].col]=1;
        for(int i=0;i<qpt;i++){
            while(l<qs[i].l) tog(seq[l]), dec(l++);
            while(l>qs[i].l) tog(seq[--l]), inc(l);
            while(r<qs[i].r) tog(seq[++r]), inc(r);
            while(r>qs[i].r) tog(seq[r]), dec(r--);
            if(qs[i].lca){
                if(qs[i].x==qs[i].y) continue;
                tog(qs[i].lca); qs[i].ans=gcd(sum[qs[i].a], sum[qs[i].b]);
                tog(qs[i].lca);
            }
            else
                qs[i].ans=gcd(sum2[qs[i].a], sum2[qs[i].b]);
        }
        sort(qs, qs+qpt, [](que a, que b){return a.id<b.id;});
    }
}
namespace tree{
    struct edge{
        int to;
        edge *next;
        edge(int t, edge *n):to(t), next(n){}
        edge(){}
    }pool[200010], *g[100010];
    int T, fa[100010], son[100010], siz[100010], top[100010], dep[100010];
    void init(){
        T=0; memset(son, 0, sizeof son);
        memset(g, 0, sizeof g);
    }
    void addedge(int u, int v){
        g[u]=&(pool[T++]=edge(v, g[u]));
        g[v]=&(pool[T++]=edge(u, g[v]));
    }
    void dfs(int p){
        siz[p]=1; mo::u[mo::T]=1; mo::seq[mo::op[p]=mo::T++]=p;
        for(edge *t=g[p];t;t=t->next){
            if(t->to==fa[p]) continue;
            fa[t->to]=p; dep[t->to]=dep[p]+1;
            dfs(t->to);
            siz[p]+=siz[t->to];
            if(siz[t->to]>siz[son[p]]) son[p]=t->to;
        }
        mo::seq[mo::ed[p]=mo::T++]=p;
    }
    void dfs2(int p, int t){
        top[p]=t;
        if(son[p]) dfs2(son[p], t);
        for(edge *t=g[p];t;t=t->next){
            if(t->to==fa[p]||t->to==son[p]) continue;
            dfs2(t->to, t->to);
        }
    }
    int lca(int u, int v){
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]]) v=fa[top[v]];
            else u=fa[top[u]];
        }
        return dep[u]<dep[v]?u:v;
    }
}
// 处理询问
void rd(que &a){
    a.lca=rd(); a.x=rd(), a.y=rd(); a.a=rd(), a.b=rd();
    if(a.lca==1) a.lca=0;
    else a.lca=tree::lca(a.x, a.y);
}
int main(){
    T=rd();
    for(int r=1;r<=T;r++){
        printf("Case #%d:\n", r);
        tree::init(); mo::init();
        n=rd(), m=rd();
        for(int i=1;i<=n;i++) arr[i].id=i, arr[i].col=rd();
        lis();
        for(int i=1;i<n;i++) tree::addedge(rd(), rd());
        tree::dfs(1); tree::dfs2(1, 1);
        for(int i=0;i<m;i++)
            rd(mo::qs[mo::qpt]), mo::qs[mo::qpt++].id=i;
        mo::go();
        for(int i=0;i<m;i++)
            printf("%lld\n", mo::qs[i].ans);
    }
    return 0;
}

希望多遇到良心出题人:)
不过也是自己菜。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值