CodeForces842C 树上dfs
题意:
有一个n个节点的数,每个点有一个点权,根到这个点的所有点权(包括这个点和根)的gcd值为这个点的答案. 对于每一个点的答案,你可以删除其到根节点的路径上的至多一个点来使答案最大. 求每个点的答案(最大值). PS:根为1号点
n,x:[1,2e5]
很显然,这一题看数据就觉得是一发dfs解决的题目,仔细想想果然如此。
一个一点也不显而易见的思想是分别讨论去掉的点在根结点上和不在根节点上的情况。
如果在根节点上,所有节点的答案一定是根结点的因数,预处理出根节点所有的因数,判断所有节点是否含有这些因数。
dfs一遍,用一个vector存储这些因数在遍历到这个点出现的次数,用一个deep表示这个点当前的深度,这些因数排序之后反向扫一遍出现的次数,如果出现的次数大于等于deep - 1,表示这个是有可能的答案。
如果不在根节点上,简单的一批,直接取根结点的答案是0,向下正常找gcd就是这个点可能的答案。
两个可能的答案比较一下取较大值。
#include <map> #include <set> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1; inline bool isdigit(const char& n) {return (n>='0'&&n<='9');} inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);} template <class T> inline bool in(T &ans){ #ifdef VSCode ans=0;T f=1;register char c; do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF); if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48; c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true; #endif #ifndef VSCode ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48; rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true; #endif }const int MAXOUT=10000; char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT; inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;} inline void out_char(char c){*(pout++)=c;if(pout==pend)write();} inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}} template <class T>inline void out_int(T x) {if(!x){out_char('0');return;} if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0; for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);} template<typename T, typename... T2> inline int in(T& value, T2&... value2) { in(value); return in(value2...); } #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second #define Vec Point typedef vector<int> VI; const double eps = 1e-9; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,tmp,K; int w[maxn]; struct Edge{ int to,next; }edge[maxn * 2]; int head[maxn],cnt; void init(){Mem(head,0);cnt = 0;}; void add(int u,int v){edge[++cnt].to = v;edge[cnt].next = head[u]; head[u] = cnt;} VI P[maxn]; int l; int ans[maxn]; int Ans[maxn]; void dfs(int root,int deep,int last){ for(int i = 0 ; i < l; i ++){ if(P[root][i]) Ans[i]++; } for(int i = l - 1; i >= 0 ; i --){ if(Ans[i] >= deep - 1){ ans[root] = max(P[1][i],ans[root]); break; } } for(int i = head[root]; i ;i = edge[i].next){ int v = edge[i].to; if(v == last) continue; dfs(v,deep + 1,root); } for(int i = 0 ; i < l ; i ++){ if(P[root][i]) Ans[i]--; } } void dfs2(int t,int GCD,int last){ ans[t] = GCD; for(int i = head[t] ; i ; i = edge[i].next){ int v = edge[i].to; if(v == last) continue; dfs2(v,__gcd(GCD,w[v]),t); } } void solve(){ for(int i = 1; i <= sqrt(w[1]); i ++){ if(!(w[1] % i)){ P[1].push_back(i); if(i != w[1] / i) P[1].push_back(w[1] / i); } } for(int i = head[1]; i ; i = edge[i].next){ int u = edge[i].to; dfs2(u,w[u],1); } sort(P[1].begin(),P[1].end()); l = P[1].size(); For(i,2,N){ for(int j = 0; j < l; j ++){ int v = P[1][j]; if(!(w[i] % v)) P[i].push_back(1); else P[i].push_back(0); } } dfs(1,1,-1); For(i,1,N){ printf("%d ",ans[i]); } } int main() { in(N); init(); For(i,1,N) in(w[i]); For(i,1,N - 1){ int u,v; in(u,v); add(u,v); add(v,u); } solve(); #ifdef VSCode write(); system("pause"); #endif return 0; }
当然也有另外的方法,由于gcd的数量较少,所以可能性也就这么点,
用vector[maxn] 表示在当前节点所有的gcd可能性,GCD表示当前到这个点一个数都没扔的可能性。
在向下递推的之后采用01背包的思想,取这个数就把这个数和上一层dp里面所有的数都gcd一遍扔进去。
不取这个数就直接将上一个数的gcd扔进去。
注意扔完之后要去重,学习到了一个简单的vector去重操作
sort(P.begin(),P.end());
erase(unique(P.begin(),P.end()),P.end());
看起来很帅
还有一个简单的输出vecotor最后一个数字的操作
Pri(P.back());
#include <map> #include <set> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1; inline bool isdigit(const char& n) {return (n>='0'&&n<='9');} inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);} template <class T> inline bool in(T &ans){ #ifdef VSCode ans=0;T f=1;register char c; do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF); if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48; c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true; #endif #ifndef VSCode ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48; rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true; #endif }const int MAXOUT=10000; char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT; inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;} inline void out_char(char c){*(pout++)=c;if(pout==pend)write();} inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}} template <class T>inline void out_int(T x) {if(!x){out_char('0');return;} if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0; for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);} template<typename T, typename... T2> inline int in(T& value, T2&... value2) { in(value); return in(value2...); } #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second #define Vec Point typedef vector<int> VI; const double eps = 1e-9; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,tmp,K; int w[maxn]; struct Edge{ int to,next; }edge[maxn * 2]; int head[maxn],cnt; void init(){Mem(head,0);cnt = 0;}; void add(int u,int v){edge[++cnt].to = v;edge[cnt].next = head[u]; head[u] = cnt;} VI dp[maxn]; int GCD[maxn]; void dfs(int t,int last){ if(~last){ GCD[t] = __gcd(GCD[last],w[t]); dp[t].pb(GCD[last]); for(int i = 0 ; i < dp[last].size(); i ++){ int v = dp[last][i]; dp[t].pb(__gcd(v,w[t])); } sort(dp[t].begin(),dp[t].end()); dp[t].erase(unique(dp[t].begin(),dp[t].end()),dp[t].end()); }else{ GCD[t] = w[t]; dp[t].pb(0); dp[t].pb(w[t]); } for(int i = head[t]; i ; i = edge[i].next){ int v = edge[i].to; if(v == last) continue; dfs(v,t); } } void solve(){ dfs(1,-1); For(i,1,N){ printf("%d ",dp[i].back()); } } int main() { in(N); init(); For(i,1,N) in(w[i]); For(i,1,N - 1){ int u,v; in(u,v); add(u,v); add(v,u); } solve(); #ifdef VSCode write(); system("pause"); #endif return 0; }