Comet OJ - Contest #11 D isaster 重构树+倍增+dfs序+线段树

发现对于任意一条边,起决定性作用的是节点编号更大的点. 

于是,对于每一条边,按照节点编号较大值作为边权,按照最小生成树的方式插入即可. 

最后用线段树维护 dfs 序做一个区间查询即可. 

Code: 

#include <bits/stdc++.h> 
#define N 400005   
#define ll long long 
#define mod 998244353    
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;             
ll val[N],mul[N<<2],V[N];        
int n,m,Q,tot,edges,tt;    
int p[N],cc[N],hd[N],to[N],nex[N],dfn[N],st[N],ed[N],size[N],Fa[21][N],F[21][N];   
struct Edge 
{
    int u,v,c; 
    Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){}  
}e[N];                                                      
void pushup(int l,int r,int now) 
{ 
    ll re=1;  
    int mid=(l+r)>>1;   
    if(l<=mid)re=re*mul[now<<1]%mod;   
    if(r>mid) re=re*mul[now<<1|1]%mod;         
    mul[now]=re;     
}
void build(int l,int r,int now) 
{
    if(l==r) 
    {
        mul[now]=V[l]%mod;        
        return;   
    } 
    int mid=(l+r)>>1;  
    if(l<=mid) build(l,mid,now<<1);   
    if(r>mid)  build(mid+1,r,now<<1|1);    
    pushup(l,r,now);         
}
void update(int l,int r,int now,int p,int v) 
{
    if(l==r) 
    {
        V[l]=mul[now]=1ll*v%mod;  
        return;   
    }  
    int mid=(l+r)>>1;      
    if(p<=mid) update(l,mid,now<<1,p,v);  
    else update(mid+1,r,now<<1|1,p,v);  
    pushup(l,r,now);       
}
ll query(int l,int r,int now,int L,int R) 
{
    if(l>=L&&r<=R) return mul[now]; 
    ll re=1;   
    int mid=(l+r)>>1;     
    if(L<=mid) re=re*query(l,mid,now<<1,L,R)%mod;   
    if(R>mid)  re=re*query(mid+1,r,now<<1|1,L,R)%mod;  
    return re;    
}
int find(int x) 
{
    return p[x]==x?x:p[x]=find(p[x]);   
} 
bool cmp(Edge a,Edge b) 
{
    return a.c<b.c;     
} 
void addedge(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;     
}
void dfs(int u,int ff) 
{
    st[u]=dfn[u]=++tt, size[u]=1, V[dfn[u]]=val[u];             
    Fa[0][u]=ff, F[0][u]=max(cc[ff], cc[u]);                
    for(int i=1;i<=20;++i) 
    {
        Fa[i][u]=Fa[i-1][Fa[i-1][u]]; 
        F[i][u]=max(F[i-1][u], F[i-1][Fa[i-1][u]]);     
    }
    for(int i=hd[u];i;i=nex[i]) 
    {    
        int v=to[i];   
        dfs(v, u);              
        size[u]+=size[v];   
    }    
    ed[u]=tt;   
}
int get(int x,int k) 
{
    for(int i=20;i>=0;--i)     
        if(Fa[i][x] && F[i][x] <= k) x=Fa[i][x];    
    return x;      
}
int main() 
{  
    int i,j,k; 
    // setIO("input"); 
    scanf("%d%d%d",&n,&m,&Q);
    tot=n;    
    for(i=1;i<N;++i) p[i]=i;   
    for(i=1;i<=n;++i) scanf("%lld",&val[i]),cc[i]=i;                  
    for(i=1;i<=m;++i)                     
    {
        scanf("%d%d",&e[i].u,&e[i].v);  
        e[i].c=max(e[i].u, e[i].v);   
    }
    sort(e+1,e+1+m,cmp);    
    for(i=1;i<=m;++i) 
    {             
        int u=e[i].u, v=e[i].v;   
        int x=find(u),y=find(v);   
        if(x!=y) 
        {
            ++tot;    
            val[tot]=1ll;   
            cc[tot]=e[i].c;    
            p[x]=tot,p[y]=tot;                                       
            addedge(tot,x), addedge(tot,y);     
        }
    }
    cc[0]=1000000000;    
    dfs(tot,0);
    build(1,tot,1);      
    for(i=1;i<=Q;++i) 
    {
        int op; 
        scanf("%d",&op);   
        if(op==1) 
        {
            int x,y; 
            scanf("%d%d",&x,&y);       
            if(x>y) printf("0\n"); 
            else 
            {  
                int k=get(x,y);    
                int L=st[k], R=ed[k];   
                printf("%lld\n",query(1,tot,1,L,R));  
            }
        }
        if(op==2) 
        {   
            int x,y; 
            scanf("%d%d",&x,&y);     
            update(1,tot,1,dfn[x],y);   
        }
    }   
    return 0;     
} 

  

猜你喜欢

转载自www.cnblogs.com/guangheli/p/11570836.html