2017 ACM-ICPC, Universidad Nacional de Colombia Programming Contest gym101466 题解
A. 给你n个不超过1e18的数字,n的数量级是1e6。从中选出两个数,做无进位加法,问最大的数能多大。
sol:将每个数字补成相同长度,除了第一个数字外,每一个数只需要在字典树上贪心的去跑就行了。查询完之后,将这个数字插入到字典树中。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline LL read(){ LL res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 20'000'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} int T[MAXN][10], tol; LL pw[25]; void Insert(LL x){ vector<int> arr; while(SZ(arr)<20){ arr.push_back(x%10); x/=10; } reverse(all(arr)); int now=0; for(int i=0;i<20;++i){ if(!T[now][arr[i]])T[now][arr[i]]=++tol; now=T[now][arr[i]]; } } LL queryMin(LL x){ LL res=0; vector<LL> arr; while(SZ(arr)<20){ arr.push_back(x%10); x/=10; } reverse(all(arr)); int now=0; for(int i=0;i<20;++i){ LL nd=0; LL mn=11; for(int j=0;j<10;++j){ if(T[now][j]){ if((arr[i]+j)%10<mn){ mn=(arr[i]+j)%10; nd=T[now][j]; } } } res+=mn*pw[19-i]; now=nd; } return res; } LL queryMax(LL x){ LL res=0; vector<LL> arr; while(SZ(arr)<20){ arr.push_back(x%10); x/=10; } reverse(all(arr)); int now=0; for(int i=0;i<20;++i){ LL nd=0; LL mx=-1; for(int j=0;j<10;++j){ if(T[now][j]){ if((arr[i]+j)%10>mx){ mx=(arr[i]+j)%10; nd=T[now][j]; } } } res+=mx*pw[19-i]; now=nd; } return res; } LL n; int main(){ pw[0]=1; for(int i=1;i<=18;++i)pw[i]=pw[i-1]*10ll; n=read(); LL ans1=(LL)1e19, ans2=0;//最大值不够大wa for(int i=1;i<=n;++i){ LL x=read(); if(i>1){ ans1=min(ans1,queryMin(x)); ans2=max(ans2,queryMax(x)); } Insert(x); } cout<<ans1<<" "<<ans2<<endl; return 0; } /* 2 1000000000000000000 1000000000000000000 */
B. 给你n个数字,表示你可以选择一个深度,这个深度每一个节点的儿子节点个数为这n个数中的一个,问最多能有多少个节点。
sol:显然从大到小排序,算一下个数就行了。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline LL read(){ LL res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} LL n; LL A[50]; int main(){ n=read(); for(int i=1;i<=n;++i)A[i]=read(); sort(A+1,A+1+n); LL ans=1; LL t=1; for(int i=n;i>=1;--i){ ans+=t*A[i]; t*=A[i]; } cout<<ans; return 0; }
C. 给定三维空间n个点,第一个点为中心点,要将中心点与其他点连线,形成一条一条直线。使得除中心点以外的其他点至少被一条直线覆盖。最少需要连多少条直线?
sol:从第二个点开始,与中心点连线。并且将其他共线的点打上标记,判断共线就用点积就行。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 5'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} struct Node{ LL x, y, z; Node(){} Node(LL _x, LL _y, LL _z){ x=_x;y=_y;z=_z; } Node operator-(const Node& a){ return Node(x-a.x,y-a.y,z-a.z); } }points[MAXN]; LL n; int vis[MAXN]; LL Dot(Node a, Node b){ return a.x*b.x+a.y*b.y+a.z*b.z; } int main(){ n=read(); for(int i=1;i<=n;++i){ points[i].x=read(); points[i].y=read(); points[i].z=read(); } int ans=0; for(int i=2;i<=n;++i){ if(vis[i])continue; else{ ++ans; for(int j=i+1;j<=n;++j){ LL t=Dot(points[i]-points[1],points[j]-points[1]); if(t*t==Dot(points[i]-points[1],points[i]-points[1])*Dot(points[j]-points[1],points[j]-points[1])){ vis[j]=1; } } } } cout<<ans<<endl; return 0; }
D. 初始时,你有一个数,值为0,你可以进行两种操作。第一种:将这个值变成2*x+1,第二种,将这个值变成2*x+2。问经过多少次操作可以将0变成一个指定的值。
sol:由于两种操作出来的值奇偶性不同,注意到这个,就可以进行逆推了。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} int n; int main(){ n=read(); string ans; while(n){ if(n&1){ ans+="A"; --n; n/=2; }else{ ans+="B"; n-=2; n/=2; } } reverse(all(ans)); cout<<ans; return 0; }
E. 给一个文本串,和一个模式串和一个整数k。问这个模式串在文本串中出现的次数>=k的最长前缀。
sol:先跑kmp的前置,得到fail指针。然后开始跑匹配的时候,可以搞出每一个文本串前缀,所匹配模式串的最大前缀,而每一个模式串的前缀,对其fail指针指向的模式串前缀是有贡献的(之所以不是所有前缀是因为,这样搞会算重)。我们跑完之后,倒着扫一遍我们的计数数组,当个数大于等于k的时候,得到答案,否则给其对应fail指针的位置加上贡献。
sol2:注意到单调性,就可以二分答案,逐个check。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} char s[MAXN]; char pat[MAXN]; int Next[MAXN]; int cnt[MAXN]; void getNext(char* str){ int len=strlen(str+1); Next[1]=0; int j=0; for(int i=2;i<=len;++i){ while(j&&str[i]!=str[j+1])j=Next[j]; if(str[i]==str[j+1])++j; Next[i]=j; } } void Match(char* s1, char* s2){ getNext(s2); int len1=strlen(s1+1); int len2=strlen(s2+1); int j=0; for(int i=1;i<=len1;++i){ while(j&&s1[i]!=s2[j+1])j=Next[j]; if(s1[i]==s2[j+1])++j; ++cnt[j]; // cout<<j<<endl; if(j==len2)j=Next[j]; } } int k; int main(){ gets(s+1); gets(pat+1); k=read(); int len1=strlen(s+1); int len2=strlen(pat+1); Match(s, pat); int ans=-1; for(int i=len2;i>=1;--i){ if(cnt[i]>=k){ ans=i; break; }else{ cnt[Next[i]]+=cnt[i]; } } if(ans==-1)cout<<"IMPOSSIBLE"; else{ for(int i=1;i<=ans;++i)cout<<pat[i]; } return 0; }
F. 判一下给的三个数能不能构成三角形。
sol:两边之和大于第三边。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} int n; int main(){ n=read(); int flag=1; for(int i=1;i<=n;++i){ vector<int> t(3); for(int j=0;j<3;++j)t[j]=read(); sort(all(t)); if(t[0]+t[1]<=t[2])flag=0; } if(flag)cout<<"YES"<<endl; else cout<<"NO"<<endl; return 0; }
G. 给你一些正整数(2<=x<=1e6),首先你要将这些数质因数分解。并且将这个质因数拼接成一个字符串,现在允许两种操作,第一是从这个字符串中取出一个数字(1<=num<=9),换成一个字母(a=1,b=2,...)。拼到一个目标字符串的后面。第二是取出两个数字,拼成一个数字。这个数字显然在(10<=num<=26)之间,同样是换成对应的字母。拼接到目标字符串的后面。问我们最终能拼成的目标字符串的种类数。
sol:首先我们有一个观察,由于x<=1e6,所以在质因数分解的过程中,拼成的字符串长度<=20。为什么这么说呢?我们考虑质因数2,长度占1,如果全是2,1e6也最多20个。对于其他的长度占1的质因数而言,贡献来的大,代价却不变,显然不会超过20个。考虑其他两位数,三位数的质因数呢?由于两个数的质因数,代价是2,贡献大于4,不会超过20位,其他同理。那么既然第一个字符串长度不超过20,这个题就变得极容易了,直接考虑状压dp,记忆化搜索就能通过了。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} int dp[(1<<20)+5]; vector<int> a; int sz; int dfs(int state){ if(dp[state]!=-1)return dp[state]; if(state==0) return 1; int& ret=dp[state]; ret=0; int vis[27]={}; for(int i=0;i<sz;++i){ if((state&(1<<i))&&a[i]!=0){ if(!vis[a[i]]){ vis[a[i]]=1; addmod(ret,dfs(state^(1<<i))); } for(int j=0;j<sz;++j){ if(i!=j&&(state&(1<<j))){ int x=a[i]*10+a[j]; if(x>=10&&x<=26&&!vis[x]){ vis[x]=1; addmod(ret,dfs(state^(1<<i)^(1<<j))); } } } } } return ret; } int main(){ int n; while(cin>>n){ memset(dp,-1,sizeof dp); a.clear(); int nn=n; for(int i=2;i*i<=nn;++i){ while(n%i==0){ int ii=i; while(ii>0){ a.PB(ii%10); ii/=10; } n/=i; } } if(n>2){ while(n>0){ a.PB(n%10); n/=10; } } sz=SZ(a); cout<<dfs((1<<sz)-1)<<endl; } return 0; }
H. C语言期末考试题(逃。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} int m; int main(){ m=read(); for(int i=1;i<=m;++i){ if(i==1){ cout<<"*"; for(int j=1;j<=m-2;++j)cout<<" "; cout<<"* "; for(int j=1;j<=m;++j)cout<<"*"; cout<<endl; }else if(i==m){ for(int j=1;j<=m;++j)cout<<"*"; cout<<" "; cout<<"*"; for(int j=1;j<=m-2;++j)cout<<" "; cout<<"*"; }else{ cout<<"*"; for(int j=1;j<=m-2;++j)cout<<" "; cout<<"* "; cout<<"*"; for(int j=1;j<=m-2;++j)cout<<" "; cout<<"*"; cout<<endl; } } return 0; }
I. 给你一个数组,你要将这个数组分成两个组,第一组的数字全都是回文串,第二组的数字里面只有4和7。问你能不能存在一种方法,使得你的分组方式,能够使得每一组的数字在原数组中距离相差不超过20。
sol:题目还是很直观的,我们显然要设计一个dp状态,dp[cur][x1][x2][s1][s2],表示当前处理到了第cur个,上一个第一组的与前一个的距离,上一个第二组的与前一个的距离,第一组的最后一个数是否有邻居,第二组的最后一个数是否有邻居(两个标志位维度是为了更好处理每组第一个)是否能分组。那么问题就来了,首先是x1,x2,要是直接开1e5,那显然会MLE(建议放到太湖之光上跑)。考虑到距离大于20的都可以认为是21,能减小空间复杂度。但是可惜的是,即使我们把dp[cur][x1][x2][s1][s2]换成bool型还是会MLE。所以我们这个时候换成bitset就可以通过(出题人老毒瘤了)。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 100'010; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} //两组分别看的话,只有这一组里前一个比较重要 //为了解决第一个的问题,引入了标记 bitset<MAXN> dp[22][22][2][2]; bitset<MAXN> vis[22][22][2][2]; int mark[MAXN]; int n, k; bool check1(int x){ vector<int> arr; while(x){ arr.push_back(x%10); x/=10; } int sz=SZ(arr); for(int i=0;i<sz/2;++i) if(arr[i]!=arr[sz-i-1])return false; return true; } bool check2(int x){ while(x){ if(x%10!=4&&x%10!=7)return false; x/=10; } return true; } bool dfs(int cur, int d1,int d2, int isOk1, int isOk2){ if(vis[d1][d2][isOk1][isOk2][cur])return dp[d1][d2][isOk1][isOk2][cur]; if(cur==n+1){ if(!isOk1||!isOk2)return 0; else return 1; } vis[d1][d2][isOk1][isOk2][cur]=1; bool ret=0; if(mark[cur]&1){ if(d1!=k+1||isOk1){ ret|=dfs(cur+1,1,min(k+1,d2+1),d1<=k?1:0,isOk2); } } if(mark[cur]&2){ if(d2!=k+1||isOk2){ ret|=dfs(cur+1,min(k+1,d1+1),1,isOk1,d2<=k?1:0); } } return dp[d1][d2][isOk1][isOk2][cur]=ret; } int main(){ n=read();k=read(); for(int i=1;i<=n;++i){ int x=read(); if(check1(x))mark[i]|=1; if(check2(x))mark[i]|=2; if(mark[i]==0){ cout<<"NO"; return 0; } } int ok=dfs(1,k+1,k+1,1,1); if(ok)cout<<"Yes"; else cout<<"No"; return 0; }
J. 先给你m个数,要组成长度为n的数组。i>m时a[i]=(a[i-m]+a[i-m+1])%mod。问你把这些数升序排列之后,q此询问,每次询问ranki。
sol:模拟即可。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 30'000'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} int cnt[MAXN]; int n, m, q; int A[MAXN]; int main(){ n=read();m=read();q=read(); for(int i=1;i<=m;++i)A[i]=read(),++cnt[A[i]]; for(int i=m+1;i<=n;++i){ A[i]=(A[i-m]+A[i-m+1])%30000000; ++cnt[A[i]]; } for(int i=1;i<=30000000;++i)cnt[i]=cnt[i]+cnt[i-1]; for(int i=1;i<=q;++i){ int x=read(); int ans=lower_bound(cnt,cnt+30000000,x)-cnt; cout<<ans<<endl; } return 0; }
K. 给你一颗树,有n个点,每一个点有点权。现在给出两种操作,第一是查询一个节点子树的所有点权乘积的因子数。第二个将树上某一个节点的值乘上val。题目保证所有数的最大素因子不超过13。
sol:子树问题当然要dfs序,考虑到最大素因子不超过13,写6颗线段树就能通过了,代码量稍大,但也是送分题。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline int read(){ int res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T a, T b){if(a>b)a=b;} template<typename T> void chmax(T a, T b){if(b>a)a=b;} #define go(e,u) for(int e=head[u];e;e=Next[e]) int to[MAXN<<1],Next[MAXN<<1],head[MAXN],tol; void add_edge(int u,int v){ Next[++tol]=head[u];to[tol]=v;head[u]=tol; Next[++tol]=head[v];to[tol]=u;head[v]=tol; } int arr[]={2,3,5,7,11,13}; inline int getid(int x){return lower_bound(arr,arr+7,x)-arr;} int n; int L[MAXN], R[MAXN], dfn, id[MAXN]; int P[MAXN<<2]; int T[MAXN<<2][6]; int val[MAXN]; void dfs(int u,int f){ L[u]=++dfn; id[dfn]=u; go(e,u){ int v=to[e]; if(v==f)continue; dfs(v,u); } R[u]=dfn; } void build1(int nd, int l, int r){ if(l==r){ P[nd]=val[id[l]]; return; } build1(lson, l, mid); build1(rson, mid+1, r); P[nd]=1ll*P[lson]*P[rson]%MOD; } void update1(int nd, int l, int r, int pos, int v){ if(l==r){ P[nd]=1ll*P[nd]*v%MOD; return; } if(pos<=mid)update1(lson, l, mid, pos, v); else update1(rson, mid+1, r, pos, v); P[nd]=1ll*P[lson]*P[rson]%MOD; } int query1(int nd, int l, int r, int L, int R){ if(L<=l&&r<=R){ return P[nd]; } int res=1; if(L<=mid)res=1ll*res*query1(lson, l, mid, L, R)%MOD; if(R>=mid+1)res=1ll*res*query1(rson, mid+1, r, L, R)%MOD; return res; } void build2(int nd, int l, int r){ if(l==r){ int x=val[id[l]]; for(int i=0;i<6;++i){ int num=0; while(x%arr[i]==0){ ++num; x/=arr[i]; } T[nd][i]+=num; } return; } build2(lson,l,mid); build2(rson,mid+1,r); for(int i=0;i<6;++i)T[nd][i]=T[lson][i]+T[rson][i]; } void update2(int nd, int l, int r, int pos, int v){ if(l==r){ int x=v; for(int i=0;i<6;++i){ int num=0; while(x%arr[i]==0){ ++num; x/=arr[i]; } T[nd][i]+=num; } return; } if(pos<=mid)update2(lson,l,mid,pos,v); else update2(rson,mid+1,r,pos,v); for(int i=0;i<6;++i)T[nd][i]=T[lson][i]+T[rson][i]; } vector<int> query2(int nd, int l, int r, int L, int R){ if(L<=l&&r<=R){ vector<int> res(6,0); for(int i=0;i<6;++i)res[i]=T[nd][i]; return res; } vector<int> res(6,0); if(L<=mid){ vector<int> t; t=query2(lson,l,mid,L,R); for(int i=0;i<6;++i)res[i]+=t[i]; } if(mid+1<=R){ vector<int>t; t=query2(rson,mid+1,r,L,R); for(int i=0;i<6;++i)res[i]+=t[i]; } return res; } int main(){ n=read(); for(int i=1;i<n;++i){ int u, v; u=read();v=read(); ++u,++v; add_edge(u,v); } dfs(1,0); for(int i=1;i<=n;++i)val[i]=read(); build1(1,1,n); build2(1,1,n); int q; q=read(); while(q--){ char buf[10]; scanf("%s",buf+1); if(buf[1]=='R'){ int w=read(); ++w; int lb=L[w],rb=R[w]; int ans=query1(1,1,n,lb,rb); vector<int> res=query2(1,1,n,lb,rb); cout<<ans<<" "; ans=1; for(int i=0;i<6;++i)ans=1ll*ans*(1+res[i])%MOD; cout<<ans<<endl; }else{ int p=read(); ++p; p=L[p]; int v=read(); update1(1,1,n,p,v); update2(1,1,n,p,v); } } return 0; }