2 条题解

  • 1
    @ 2023-10-24 0:06:30
    #include <bits/stdc++.h>
    #define N 1000005
    using namespace std;
    typedef long long ll;
    
    template <typename T>
    inline void read(T &num) {
    	T x = 0; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar());
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
    	num = x; 
    }
    
    const ll mod = 998244353;
    int n, m, Q, F[N];
    int head[N], pre[N<<1], to[N<<1], sz, inde[N];
    ll a[N];
    
    inline void addedge(int u, int v) {
    	pre[++sz] = head[u]; head[u] = sz; to[sz] = v; inde[v]++;
    }
    
    struct oper {
    	int tp, p;
    	ll v, mul, sum; 
    } b[N];
    
    queue<int> q;
    int ord[N], bnbn;
    void toposort() { //拓扑排序
    	for (int i = 1; i <= m; i++) if (!inde[i]) q.push(i);
    	while (!q.empty()) {
    		int x = q.front(); q.pop();
    		ord[++bnbn] = x;
    		for (int i = head[x]; i; i = pre[i]) {
    			int y = to[i];
    			inde[y]--;
    			if (!inde[y]) q.push(y);
    		}
    	}
    }
    
    void getmul() { //计算节点的mul
    	for (int i = m; i; i--) {
    		int x = ord[i];
    		for (int j = head[x]; j; j = pre[j]) {
    			int y = to[j];
    			b[x].mul = b[x].mul * b[y].mul % mod;
    		}
    	} 
    }
    
    void getsum() { //下传节点的sum
    	for (int i = 1; i <= m; i++) {
    		int x = ord[i]; ll now = 1;
    		for (int j = head[x]; j; j = pre[j]) {
    			int y = to[j];
    			b[y].sum = (b[y].sum + b[x].sum * now % mod) % mod;
    			now = now * b[y].mul % mod;
    		}
    	}
    }
    
    int main() {
    	read(n); 
    	for (int i = 1; i <= n; i++) read(a[i]); 
    	read(m);
    	for (int i = 1; i <= m; i++) {
    		read(b[i].tp);
    		if (b[i].tp == 1) {
    			read(b[i].p); read(b[i].v);
    			b[i].mul = 1;
    		} else if (b[i].tp == 2) {
    			read(b[i].v); b[i].mul = b[i].v;
    		} else {
    			read(b[i].p); b[i].mul = 1;
    			for (int j = 1, x; j <= b[i].p; j++) {
    				read(x);
    				addedge(i, x);
    			}
    		}
    	}
    	toposort(); 
    	getmul();
    	read(Q); ll now = 1;
    	for (int i = 1; i <= Q; i++) read(F[i]);
    	for (int i = Q; i; i--) {
    		int x = F[i]; b[x].sum = (b[x].sum + now) % mod;
    		now = now * b[x].mul % mod;
    	}
    	getsum();
    	for (int i = 1; i <= n; i++) a[i] = a[i] * now % mod;
    	for (int i = 1; i <= m; i++) {
    		if (b[i].tp == 1) {
    			a[b[i].p] = (a[b[i].p] + b[i].v * b[i].sum % mod) % mod;
    		}
    	}
    	for (int i = 1; i <= n; i++) printf("%lld ", a[i]);
    	return 0; 
    }**
    
    • 0
      @ 2022-8-20 13:38:31
      #include<cstdio>
      #include<algorithm>
      #include<vector>
      #include<queue>
      
      const int N=100005,P=998244353;
      
      int n,m,Q;
      std::vector<int> G1[N],G2[N];
      //为了求快(写代码快,不是运行快)考试时的图我全用vector了,,,
      //G2是函数调用图,G1是G2的反图用于第一遍拓扑排序
      
      int cnt[N];//记录每个函数的执行次数
      
      int data[N],tp[N],mul[N],add[N],pos[N];
      //data:原序列
      //tp:记录每个操作的类型
      //mul:记录每个操作执行一次后会把序列乘多少,操作1和3初始化为1,操作2初始化为读入数据、
      //add:记录操作1的加数
      //pos:记录操作1的操作位置
      
      
      
      
      int deg1[N];
      void topo1()//用于算出每个函数执行完会将序列乘多少
      //事实上用记忆化搜索更简单,,,
      {
      	static std::queue<int> q;
      	for(int i=0;i<=m;++i)
      	{
      		deg1[i]=G2[i].size();
      		if(deg1[i]==0)q.push(i);
      	}
      	while(!q.empty())
      	{
      		int u=q.front();
      		q.pop();
      		for(int i=0;i!=G1[u].size();++i)
      		{
      			int v=G1[u][i];
      			mul[v]=(long long)mul[v]*mul[u]%P;//直接递推,很容易
      			--deg1[v];
      			if(deg1[v]==0)q.push(v);
      		}
      	}
      }
      
      
      
      
      
      int deg2[N];
      void topo2()//用于算出每个函数的调用次数
      {
      	static std::queue<int> q;
      	for(int i=0;i<=m;++i)
      	{
      		deg2[i]=G1[i].size();
      		if(deg2[i]==0)q.push(i);
      	}
      	while(!q.empty())
      	{
      		int u=q.front();
      		int now_mul=1;//当前函数内的乘法标记
      		q.pop();
      		for(int i=G2[u].size();i!=0;--i)
               //注意这里要倒着遍历边表
               //因为每个函数执行完乘的倍数只影响在它前面执行的函数
      		{
      			int v=G2[u][i-1];
      			cnt[v]=(cnt[v]+(long long)cnt[u]*now_mul)%P;
                   //当前乘法标记可以转化为前一个函数的执行次数
      			now_mul=(long long)now_mul*mul[v]%P;
      			--deg2[v];
      			if(deg2[v]==0)q.push(v);
      		}
      	}
      }
      
      
      
      #include<cctype>
      char gc()
      {
      	static char buf[1<<16],*p1=buf,*p2=buf;
      	if(p1==p2)
      	{
      		p2=(p1=buf)+fread(buf,1,1<<16,stdin);
      		if(p1==p2)return EOF;
      	}
      	return *p1++;
      }
      
      template<typename _Tp>
      void read(_Tp &x)
      {
      	x=0;
      	char c=gc();
      	while(!isdigit(c))c=gc();
      	while(isdigit(c))x=x*10-48+c,c=gc();
      }
      
      
      int main()
      {
      	read(n);
      	for(int i=1;i<=n;++i)read(data[i]);
      	read(m);
      	mul[0]=1;
      	for(int i=1;i<=m;++i)
      	{
      		read(tp[i]);
      		if(tp[i]==1)
      		{
      			read(pos[i]),read(add[i]);
      			mul[i]=1;
      		}
      		if(tp[i]==2)
      		{
      			read(mul[i]);
      		}
      		if(tp[i]==3)
      		{
      			mul[i]=1;
      			int len;
      			read(len);
      			for(int j=0;j<len;++j)
      			{
      				int v;
      				read(v);
      				G1[v].push_back(i);
      				G2[i].push_back(v);
      			}
      		}
      	}
      	read(Q);
      	cnt[0]=1;//把0号函数作为主函数
      	for(int i=0;i<Q;++i)
      	{
      		int x;
      		read(x);
      		G2[0].push_back(x);
      		G1[x].push_back(0);
      	}
      	topo1();
      	topo2();
      	for(int i=1;i<=n;++i)data[i]=(long long)data[i]*mul[0]%P;
          //!!!不要忘记主函数本身的乘法标记对答案的影响!!!
      	for(int i=1;i<=m;++i)
      	{
      		if(tp[i]==1)//对于每个操作1,由于没有了操作2和3的影响,可以直接计算答案
      		{
      			data[pos[i]]=(data[pos[i]]+(long long)cnt[i]*add[i])%P;
      		}
      	}
      	for(int i=1;i<=n;++i)
      	{
      		printf("%d ",data[i]);
      	}
      }
      
      • 1

      信息

      ID
      109
      时间
      2000ms
      内存
      256MiB
      难度
      8
      标签
      递交数
      13
      已通过
      7
      上传者