Comet OJ - Contest #11 isaster

6 篇文章 0 订阅
2 篇文章 0 订阅
题意

你需要支持对一张 n 个点 m 条边点带权的无向连通图进行以下两种操作:
1、修改点 x 的点权。
2、询问从点 x 出发只经过编号不大于 y 的点能到达的所有点的点权之积取模 998244353

题解

对操作分块,每块内的答案一起求
求解时,按编号从小到大加入图中,维护所有联通块的点权的乘积
每次加完一个点,遍历和这个点有关的操作2,初始答案就是询问点所在的联通块的点权乘积
但是有修改
每次得到一个初始答案时,从块的起点开始遍历操作1,这些操作中,对当前答案有影响的,其修改的点所在的联通块必定和求解的点在一起,然后就更新一下答案即可

坑点是,点权的取值可以大于模数,就是说,当点权为998244353时,求的是0的逆元,是不存在的,所以要特殊处理一下

代码
#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f3f3f3f
#define eps 1e-5
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<"      :   "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef  pair<int,int> pp;

int fa[N],a[N],la[N],ans[N],qe[N],num[N],cnt,n,m,Q;
LL inv[N],s[N];
struct cc{int x,y; }G[N<<1];

inline void add(int x,int y){G[++cnt]={y,la[x]}; la[x]=cnt;}

struct node{
    int op,x,y;
}q[N];

namespace IO{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    #define ll long long
    //fread->read
    bool IOerror=0;
    inline char nc(){
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend){
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1){IOerror=1;return -1;}
        }
        return *p1++;
    }
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
    inline void read(int &x){
        bool sign=0; char ch=nc(); x=0;
        for (;blank(ch);ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    //fwrite->write
    struct Ostream_fwrite{
        char *buf,*p1,*pend;
        Ostream_fwrite(){buf=new char[BUF_SIZE];p1=buf;pend=buf+BUF_SIZE;}
        void out(char ch){
            if (p1==pend){
                fwrite(buf,1,BUF_SIZE,stdout);p1=buf;
            }
            *p1++=ch;
        }
        void print(int x){
            static char s[15],*s1;s1=s;
            if (!x)*s1++='0';if (x<0)out('-'),x=-x;
            while(x)*s1++=x%10+'0',x/=10;
            while(s1--!=s)out(*s1);
        }
        void print(char *s){while (*s)out(*s++);}
        void flush(){if (p1!=buf){fwrite(buf,1,p1-buf,stdout);p1=buf;}}
        ~Ostream_fwrite(){flush();}
    }Ostream;
    inline void print(int x){Ostream.print(x);}
    inline void print(char *s){Ostream.print(s);}
};
using namespace IO;

int getfa(int x){
    return fa[x]==x?x:fa[x]=getfa(fa[x]);
}

inline void UNI(int a,int b){
    int i=getfa(a),j=getfa(b);
    if (i!=j) 
    {
        fa[i]=j;
        s[j]=s[j]*s[i]%mod;
        num[j]+=num[i];
    }
}

inline LL qpow(LL a,LL b){
    LL res=1;
    while(b){
        if (b&1) res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
inline void slove(int st,int ed){
    vector<pp> v[N]; int cnt=0;

    for(int i=1;i<=n;i++) 
    {
        fa[i]=i;
        if (a[i]) s[i]=a[i],num[i]=0;
        else num[i]=s[i]=1;
    }
    for(int i=st;i<=ed;i++) if (q[i].op==1) 
        if (q[i].x<=q[i].y) v[q[i].y].pb(pp(q[i].x,i));else;
    else{
        inv[i]=qpow(a[q[i].x],mod-2),a[q[i].x]=q[i].y, qe[++cnt]=i;
    }

    for(int i=1;i<=n;i++){
        for(int j=la[i];j;j=G[j].y) UNI(i,G[j].x);

        for(auto j:v[i]){
            int t=getfa(j.fi);
            LL tmp=s[t],tt=num[t];
            for(int k=1;k<=cnt&&qe[k]<j.se;k++) if (getfa(q[qe[k]].x)==t)
            {
                if (inv[qe[k]]==0) tt--; else tmp=tmp*inv[qe[k]]%mod; 
                if (q[qe[k]].y) tmp=tmp*q[qe[k]].y%mod; else tt++;
            }
            if (tt) ans[j.se]=0; else ans[j.se]=tmp;
        }
    }
}

int main(int argc, char const *argv[]){
    read(n);read(m);read(Q);
    for(int i=1;i<=n;i++) read(a[i]),a[i]%=mod;
    for(int i=1;i<=m;i++){
        int x,y; read(x); read(y); if (x==y) continue; if (x<y) swap(x,y);
        add(x,y);
    }
    for(int i=1;i<=Q;i++) read(q[i].op), read(q[i].x), read(q[i].y),q[i].y%=mod;

    int block=min(sqrt(Q)*5,1.0*Q);

    for(int i=1;i<=Q;i+=block) slove(i,min(i+block-1,Q));

    for(int i=1;i<=Q;i++) if (q[i].op==1) 
            print(ans[i]%mod),Ostream.out('\n');

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值