zoukankan      html  css  js  c++  java
  • [jzoj 6086] [GDOI2019模拟2019.3.26] 动态半平面交 解题报告 (set+线段树)

    题目链接:

    https://jzoj.net/senior/#main/show/6086

    题目:

    题解:

    • 一群数字的最小公倍数就是对它们质因数集合中的每个质因数的指数取$max$然后相乘
    • 这样的子树查询一般都与$dfs$序有关
    • 不妨把一个质因数$p$拆分成$p^1,p^2,p^3...$这样若干种颜色,每种颜色对答案的贡献都是$p$
    • 我们从另一个角度来考虑如何处理“不同的数”。先不管深度,考虑两个点权相等的节点$u$和$v$,点权为$val$,他们自己的贡献是使得所有子树内包含他的节点答案乘以$val$,现在考虑重复了的贡献,同时包含$u$和$v$的节点答案被乘了两次,即包含$lca(u,v)$的节点答案需要被除去一个$val$。
    • 多个节点的时候,只需按$dfs$序排序,相邻两个的$lca$处除即可。现在我们要考虑深度,只需要将询问离线并按深度排序,节点按深度排序后一个一个加入即可。维护点权相同的点可以用$set$,维护$dfs$序用线段树。这是一个很经典的做法
    • 在线的话,把线段树可持久化即可

    代码:

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    
    const int N=1e5+15;
    const int M=1e7+15;
    const int mo=998244353;
    int n,tot;
    int a[N],head[N];
    set <int> s[N*30];
    map<int,int>hsh;
    struct EDGE
    {
        int to,nxt;
    }edge[N<<1];
    inline int read()
    {
        char ch=getchar();int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    } 
    int cnt;
    int prime[M],mn[M],vis[M];
    void pre()
    {
        mn[1]=1;
        for (int i=2;i<M;i++)
        {
            if (!vis[i]) prime[++cnt]=i,mn[i]=i;
            for (int j=1;j<=cnt&&prime[j]*i<M;j++)
            {
                vis[prime[j]*i]=1;mn[prime[j]*i]=prime[j];
                if (i%prime[j]==0) break;
            }
        }
    }
    int qpow(int a,int b)
    {
        int re=1;
        for (;b;b>>=1,a=1ll*a*a%mo) if (b&1) re=1ll*re*a%mo;
        return re;
    }
    void add(int u,int v)
    {
        edge[++tot]=(EDGE){v,head[u]};
        head[u]=tot;
    }
    int tim;
    int fa[N][21],st[N],ed[N],dep[N],tid[N];
    void dfs(int x,int p)
    {
        dep[x]=dep[p]+1;
        st[x]=++tim;tid[tim]=x;
        fa[x][0]=p;
        for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
        for (int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if (y==p) continue;
            dfs(y,x);
        }
        ed[x]=tim;
    }
    int lca(int x,int y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        for (int i=20;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
        if (x==y) return x;
        for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    bool cmp(const int &a,const int &b) {return dep[a]<dep[b];}
    int idx;
    int get(int x)
    {
        if (!hsh[x]) hsh[x]=++idx;
        return hsh[x]; 
    }
    int sz;
    int rt[N],mul[N*600],ls[N*600],rs[N*600];
    void ins(int &o,int lst,int l,int r,int x,int y)
    {
        o=++sz;
        mul[o]=1ll*mul[lst]*y%mo;
        ls[o]=ls[lst];rs[o]=rs[lst];
        if (l==r) return;
        int mid=l+r>>1;
        if (x<=mid) ins(ls[o],ls[lst],l,mid,x,y);
        else ins(rs[o],rs[lst],mid+1,r,x,y);
    }
    int query(int o,int l,int r,int x,int y)
    {
        if (l>=x&&r<=y) return mul[o];
        int mid=l+r>>1,re=1;
        if (x<=mid) re=1ll*re*query(ls[o],l,mid,x,y)%mo;
        if (y>mid) re=1ll*re*query(rs[o],mid+1,r,x,y)%mo;
        return re;
    }
    int b[N]; 
    int main()
    {
        freopen("half.in","r",stdin);
        freopen("half.out","w",stdout);
        pre();
        int k=read();n=read();
        for (int i=1;i<=n;i++) a[i]=read(),b[i]=i;
        for (int i=1;i<n;i++)
        {
            int u=read(),v=read();
            add(u,v);add(v,u);
        } 
        dfs(1,0);
        mul[0]=1;
        sort(b+1,b+1+n,cmp);
        set<int>::iterator it1,it2,it3;
        for (int i=1;i<=n;i++)
        {
            int u=b[i],d=dep[u],tmp=a[u];
            rt[d]=rt[dep[b[i-1]]];
            while (tmp>1)
            {
                int t=mn[tmp],it=qpow(t,mo-2),z=1;
                while (tmp%t==0)
                {
                    tmp/=t;
                    z*=t;
                    int y=get(z);
                    s[y].insert(st[u]);
                    it2=s[y].lower_bound(st[u]);
                    it1=it2;
                    if (it1!=s[y].begin()) --it1;
                    it3=it2;
                    ++it3;
                    ins(rt[d],rt[d],1,n,st[u],t);
                    int u1=0,u2=0;
                    if (it2!=s[y].begin())
                    {
                        u1=tid[*it1];int L=lca(u1,u);
                        ins(rt[d],rt[d],1,n,st[L],it);
                    }
                    if (it3!=s[y].end())
                    {
                        u2=tid[*it3];int L=lca(u2,u);
                        ins(rt[d],rt[d],1,n,st[L],it);
                    }
                    if (u1&&u2)
                    {
                        int L=lca(u1,u2);
                        ins(rt[d],rt[d],1,n,st[L],t);
                    }
                }
            }
        }
        for (int i=dep[b[n]]+1;i<=n;i++) rt[i]=rt[i-1];
        int q=read(),ans=0;
        while (q--)
        {
            int u=read()^(k*ans),d=min(n,dep[u]+read()^(k*ans));
            printf("%d
    ",query(rt[d],1,n,st[u],ed[u]));
        }
        return 0;
    }
  • 相关阅读:
    如何更改Linux yum源?
    Vsftp设置为PASV mode(被动模式传送)
    CentOS 6.5 yum安装配置lnmp服务器(Nginx+PHP+MySQL)
    centos6.3搭建FTP服务器图文教程
    Linux关闭/开启防火墙命令
    linux下火狐浏览器安装flash player插件
    判断网站织梦DedeCms版本的方法
    PHP获取当前url路径的函数及服务器变量
    leetcode 205 Isomorphic Strings
    leetcode 70 Climbing Stairs
  • 原文地址:https://www.cnblogs.com/xxzh/p/10613079.html
Copyright © 2011-2022 走看看