First, begin by learning from the template title -
P3387 [template] point reduction
Ideas:
1. Why should shrink this question point? (When do I need reduced points)
According to the meaning of the title, we just need to find the maximum point of a path right on the line, do not limit the number of points. Then consider a point on one of the rings is chosen, it is not a whole ring should have been selected, it must be very good, why not selected can be chosen. It is critical that the subject also allows us to repeat after one edge or a point, we do not need to consider the other. Thus the entire ring may actually be regarded as a point (a point where the option should be selected from other points)
- excerpt from the first chapter explanations Los Valley
2. The strongly connected components condensing point -> be built edge DAG -> DPmax
1 #include<cstdio> 2 #include<queue> 3 #include<vector> 4 #include<cstring> 5 #include<algorithm> 6 #define N 100010 7 #define M 500010 8 using namespace std; 9 10 struct node{ 11 int from,to,next; 12 }edge[M]; 13 queue < int > q; 14 vector < int > cd[N]; //出度 15 vector < int > rd[N]; //入度 16 int ans[M],t,x,y,v,rds[N],u,n,m,sum,vis[N],d[N],dis[N]; 17 int dfn[N],low[N],f[N],time,cnt,k; 18 int stack[N],head[M],visit[N],tot,id; 19 20 void add(int x,int y){ //邻接表加边 21 edge[++cnt].next=head[x]; 22 edge[cnt].from=x; 23 edge[cnt].to=y; 24 head[x]=cnt; 25 } 26 27 voidTarjan ( int X) { 28 DFN [X] = Low [X] Time = ++; // update 29 Stack [ID ++] = X; // handwritten stack 30 Visit [X] = . 1 ; // into stack 31 is for ( int I = head [X]; I; I = Edge [I] .next) { 32 IF (! DFN [Edge [I] .to]) { // is not updated to point 33 is Tarjan (Edge [I] .to); 34 is Low [X] = min (Low [X], Low [Edge [I] .to]); 35 } 36 the else { 37 [ IF(Visit [Edge [I] .to]) // updated point 38 is Low [X] = min (Low [X], DFN [Edge [I] .to]); 39 } 40 } 41 is IF (Low [ X] == DFN [X]) { // note is not in the for loop 42 is TOT ++; // strongly connected component number (condensing point number) 43 is the while ( . 1 ) { 44 is VIS [Stack [ID]] = TOT; / / VIS record number condensing point 45 DIS [TOT] + = D [Stack [ID]]; // weight reduction point value = strongly connected components accumulated weights 46 is Visit [Stack [ID]] = 0 , ID- ; //Stack 47 IF (X == Stack [+ ID . 1 ]) BREAK ; // this communication block is completed shells 48 } 49 } 50 } 51 is void TOPO () { // topological sort 52 is for ( int I = . 1 ; I < TOT =; I ++) IF (RDS [I] == 0 ) q.push (I); // into degrees (RDS) is 0, into the team 53 is the while ! ( q.empty ()) { 54 is int U = Q .front (); 55 q.pop (); // teams head out team 56 is ANS [K ++] = U; // ANS arranged in order of recording topologically point 57 is for ( int I = . 1 ; I <= CD [U] .size (); I ++) { // CD [U]. size (): length cd [u] [] of 58 V CD = [U] [I- . 1 ]; // because the vector is zero, so the reduction. 1 59 RDS [V] -; // the degree - 60 IF (RDS [V] == 0 ) q.push (V); // into degrees (RDS) is 0, into the team 61 is } 62 is } 63 is } 64 65 int main () 66 { 67 scanf("%d%d",&n,&m); 68 for(int i=1;i<=n;i++) scanf("%d",&d[i]); 69 for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),add(x,y); 70 71 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); // tarjan缩点 72 73 for(int i=1; I <= CNT; I ++) { // the condensing point to build a good side -> the DAG 74 IF (VIS [Edge [I]. from ] =! VIS [Edge [I] .to]) { 75 X = VIS [edge [I]. from ], Y = VIS [edge [I] .to]; // build x-> y side 76 RDS [Y] ++; // Y into degrees ++ 77 RD [Y ] .push_back (x); // in the x-y of penetration into 78 CD [x] .push_back (y); // put into x y outdegree 79 } 80 } 81 TOPO (); // the DAG topology run on 82 for( Int I = . 1 ; I <= TOT; I ++) { // topologically sequence (no aftereffect) runs the DP 83 int W = ANS [I]; 84 F [W] = DIS [W]; 85 for ( int J = . 1 ; J <= RD [W] .size (); J ++ ) 86 F [W] = max (F [W], F [RD [W] [J- . 1 ]] + DIS [W]) ; // because the vector is zero, so the reduction. 1 87 } 88 89 for ( int I = . 1 ; I <= TOT; I ++) max = SUM (F [I], SUM); // final tally answer 90 printf ( "%d",sum); 91 return 0; 92 }
P3388 [template] point cut (top cut)
1 #include<cstdio> 2 #include<algorithm> 3 #define N 100010 4 using namespace std; 5 struct node{ 6 int next,to; 7 }edge[N*2]; 8 int n,m,dfn[N],cut[N],head[N],low[N],tot,cnt,id; 9 10 void add(int x,int y){ 11 edge[++cnt].next=head[x]; 12 edge[cnt].to=y; 13 head[x]=cnt; 14 } 15 16 void tarjan(int x,int root){ //割点 17 int child=0; 18 dfn[x]=low[x]=++id; 19 for(int v,i=head[x];i;i=edge[i].next){ 20 v=edge[i].to; 21 if(!dfn[v]){ //没有更新过的 22 tarjan(v,root); 23 low[x]=min(low[x],low[v]); 24 if(low[v]>=dfn[x]&&x!=root) cut[x]=1; // x is not a root cut point judgment conditions: Low [V]> = DFN [x] 25 IF (x == the root) Child ++; // if x is a root 26 is } 27 the else IF (! X = the root) Low [X] = min (Low [X], DFN [V]); 28 } 29 IF (Child> = 2 && the root == X) Cut [X] = . 1 ; // X root of cut point judgment condition: YES two or more sub-trees 30 } 31 is int main () 32 { 33 is Scanf ( " % D% D " , & n-, & m); 34 is for ( int U, V, I = . 1;i<=m;i++){ 35 scanf("%d%d",&u,&v); 36 add(u,v),add(v,u); 37 } 38 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i); 39 for(int i=1;i<=n;i++) if(cut[i]) tot++; 40 printf("%d\n",tot); 41 for(int i=1;i<=n;i++) if(cut[i]) printf("%d ",i); 42 return 0; 43 }