「泉七培训 – 杨国烨」出纳员zgg
「题目描述」
zgg去当出纳员了!zgg所在的公司的工资是按年发放的。在每年的元旦,每个员工的工资额会被修改为0元;在每年的除夕,员工按工资额领取相应的工资。zgg的上司是一位和蔼可亲的老爷爷,他经常给员工们提升工资。而zgg的工作,就是帮助所有员工统计最后的工资额。
老爷爷只会用以下两种指令给员工们提升工资:1.让某个员工的工资额提升X元;2.让所有员工的工资额变成原来的X倍。
然则,由于老爷爷实在是太和蔼了,以至于提升工资的指令数目达到了10^10级别,这无疑使zgg的工作变得困难重重。
还好,老爷爷的指令最多只有N种。为了提高工作效率,zgg又定义了一些宏指令:某个宏指令包括2个分指令(可以是宏指令或基本指令),执行宏指令相当于先后执行这两个分指令。
许多年后,zgg发现,这些指令构成了一棵二叉树:如果把宏指令当成某个结点,那么两个分指令则相当于该结点的左右儿子,而叶子结点就是那些基本指令。
现在,除夕即将来临,zgg却发现自己的工作一点都没
有完成!还好,所有的指令都按顺序记录下来了。为了自己的工资,zgg想请你帮忙,统计出所有人的工资。
「输入格式」
第一行三个正整数N,M,Q,分别表示基本指令的种类数目、所有指令的数目、员工数目。
接下来N行,第i+1行代表第i种指令(基本指令),有两种类型:
1.每行3个整数1 X Y:表示让X号员工的工资额提升Y元;
2.每行2个整数2 X:表示让所有员工的工资额变为原来的X倍。
接下来N-1行,第i+N+1行代表第i+N种指令(宏指令),每行2个正整数A B,表示第i+N种指令的分指令。
接下来M行,每行一个正整数A,表示执行A指令。
「输出格式」
共Q行,每行一个整数Ansi,表示第i号员工最后的工资。
「样例输入」
4 5 2
1 2 3
1 1 1
2 2
1 1 10
6 7
2 1
3 4
2
6
7
5
3
「样例输出」
80
36
「数据规模和约定」
有50%的数据平均分布在测试点中,满足:基本指令均为第1种指令。
30%的数据满足N<=200,M<=200,Q<=100;
60%的数据满足N<=10000,M<=20000,Q<=100;
100%的数据满足N,M,Q<=100000,所有员工任何时候的工资额都不会超过10^9元。
第一种指令1 X Y满足1<=X<=Q,0<=Y<=100;
第二种指令2 X满足0<=X<=10。
题解。。。
因为所有员工任何时候工资不超过10^9,所以有效的乘法操作不超过31个,*1视为+0
那么依次处理宏指令,若这个宏指令的子树中无乘法运算则打标记,若有乘法运算暴力处理整棵树的标记再暴力执行这个宏指令
但是注意到有*0的操作
所以应该从最后一个有子树中有*0的宏指令开始做,前面的无视,这样才能保证复杂度
但是还有一个问题,所有其余的乘法操作并不一定都有效!可能序列全为0时,执行一堆乘法。。。
还要记录下每个宏指令是否有有效的加法操作,序列都为0的时候无视乘法
最后似乎还有一种情况,最后一个有子树中有*0的宏指令执行之后,不好确定序列是否全0,嗯暴力判断一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
#include<cstdio> #include<cmath> #include<ctime> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<set> #define ll long long #define mod 1000000007 #define inf 1000000000 using namespace std; int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int N,M,Q,root,start; int opt[100005],x[100005],y[100005]; int ls[200005],rs[200005],d[200005],A[100005]; int tag[200005],ans[200005]; bool zero[200005],mul[200005],add[200005]; void dp(int x) { if(!ls[x])return; dp(ls[x]);dp(rs[x]); mul[x]|=(mul[ls[x]]|mul[rs[x]]); zero[x]|=(zero[ls[x]]|zero[rs[x]]); add[x]|=(add[ls[x]]|add[rs[x]]); } void pushdown(int x) { int l=ls[x],r=rs[x]; tag[l]+=tag[x]; tag[r]+=tag[x]; tag[x]=0; } void solve(int k) { if(!ls[k]) { if(opt[k]==1)ans[x[k]]+=tag[k]*y[k]; else if(tag[k]) for(int i=1;i<=Q;i++) ans[i]*=x[k]; tag[k]=0; return; } pushdown(k); solve(ls[k]);solve(rs[k]); } int main() { N=read();M=read();Q=read(); for(int i=1;i<=N;i++) { opt[i]=read(); if(opt[i]==1) { x[i]=read(),y[i]=read(); if(y[i])add[i]=1; } else { x[i]=read(); if(x[i]==1)opt[i]=1; else { mul[i]=1; if(x[i]==0)zero[i]=1; } } } for(int i=N+1;i<2*N;i++) { ls[i]=read(),rs[i]=read(); d[ls[i]]++;d[rs[i]]++; } for(int i=N+1;i<2*N;i++) if(!d[i])root=i; dp(root); for(int i=1;i<=M;i++)A[i]=read(); start=1; for(int i=1;i<=M;i++) if(zero[A[i]])start=i; bool flag=0; for(int i=start;i<=M;i++) { if(add[A[i]]) { flag=1; if(zero[A[i]]) { flag=0; for(int i=1;i<=Q;i++)if(ans[i]!=0)flag=1; } } if(mul[A[i]]) { if(!flag)continue; solve(root); tag[A[i]]=1; solve(A[i]); } else tag[A[i]]++; } solve(root); for(int i=1;i<=Q;i++)printf("%d\n",ans[i]); return 0; } |