poi
Posted fcwww
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poi相关的知识,希望对你有一定的参考价值。
[POI2007]MEG-Megalopolis
题意:https://www.luogu.org/problemnew/show/P3459
分析:发现查询的起点总是1。把边下放到点,树剖裸上。注意1号点是不要的。
代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 using namespace std;
5 #define N 250050
6 #define lson pos<<1
7 #define rson pos<<1|1
8 int head[N],to[N<<1],nxt[N<<1],cnt,tot;
9 int n,m,dep[N],fa[N],son[N],siz[N],top[N],idx[N];
10 int t[N<<2];
11 char ch[10];
12 void read(int &x)
13 {
14 int f=1;x=0;char s=getchar();
15 while(s<\'0\'||s>\'9\'){if(s==\'-\')f=-1;s=getchar();}
16 while(s>=\'0\'&&s<=\'9\'){x=(x<<3)+(x<<1)+s-\'0\';s=getchar();}
17 x*=f;
18 }
19 inline void add(int u,int v)
20 {
21 to[++cnt]=v;
22 nxt[cnt]=head[u];
23 head[u]=cnt;
24 }
25 void dfs1(int x,int y)
26 {
27 dep[x]=dep[y]+1;
28 fa[x]=y;
29 siz[x]=1;
30 for(int i=head[x];i;i=nxt[i])
31 {
32 if(to[i]==y)continue;
33 dfs1(to[i],x);
34 siz[x]+=siz[to[i]];
35 if(siz[to[i]]>siz[son[x]])
36 {
37 son[x]=to[i];
38 }
39 }
40 }
41 void dfs2(int x,int t)
42 {
43 top[x]=t;idx[x]=++tot;
44 if(son[x])dfs2(son[x],t);
45 for(int i=head[x];i;i=nxt[i])
46 {
47 if(to[i]==fa[x]||to[i]==son[x])continue;
48 dfs2(to[i],to[i]);
49 }
50 }
51 void bt(int l,int r,int pos)
52 {
53 if(l==r)
54 {
55 t[pos]=1;return ;
56 }
57 int mid=l+r>>1;
58 bt(l,mid,lson);
59 bt(mid+1,r,rson);
60 t[pos]=t[lson]+t[rson];
61 }
62 void up(int l,int r,int x,int y,int pos)
63 {
64 if(t[pos]==0)return ;
65 if(x<=l&&r<=y)
66 {
67 t[pos]=0;return ;
68 }
69 int mid=l+r>>1;
70 if(x<=mid)up(l,mid,x,y,lson);
71 if(y>mid)up(mid+1,r,x,y,rson);
72 t[pos]=t[lson]+t[rson];
73 }
74 int query(int l,int r,int x,int y,int pos)
75 {
76 if(x<=l&&r<=y)return t[pos];
77 int re=0,mid=l+r>>1;
78 if(x<=mid)re+=query(l,mid,x,y,lson);
79 if(y>mid)re+=query(mid+1,r,x,y,rson);
80 return re;
81 }
82 int main()
83 {
84 scanf("%d",&n);
85 bt(1,n,1);
86 int x,y;
87 for(int i=1;i<n;i++)
88 {
89 scanf("%d%d",&x,&y);
90 add(x,y);
91 add(y,x);
92 }
93 dfs1(1,0);
94 dfs2(1,1);
95 scanf("%d",&m);
96 for(int i=1;i<n+m;i++)
97 {
98 scanf("%s",ch);
99 if(ch[0]==\'W\')
100 {
101 scanf("%d",&x);
102 y=1;
103 int ans=0;
104 while(top[x]!=top[y])
105 {
106 if(dep[top[x]]>dep[top[y]])swap(x,y);
107 ans+=query(1,n,idx[top[y]],idx[y],1);
108 y=fa[top[y]];
109 }
110 if(dep[x]<dep[y])swap(x,y);
111 ans+=query(1,n,idx[y],idx[x],1);
112 printf("%d\\n",ans-1);
113 }
114 else
115 {
116 scanf("%d%d",&x,&y);
117 if(x>y)swap(x,y);
118 if(x==1)
119 {
120 up(1,n,idx[y],idx[y],1);
121 }
122 else if(fa[x]==y)
123 {
124 up(1,n,idx[x],idx[x],1);
125 }
126 else
127 {
128 up(1,n,idx[y],idx[y],1);
129 }
130 }
131 }
132 }
[POI2007]ZAP-Queries
这里:http://www.cnblogs.com/suika/p/8416136.html
[POI2008]PLA-Postering
题意:https://www.luogu.org/problemnew/show/P3467
分析:维护一个单调增的栈,如果当前高度大于栈顶,ans+1;否则弹栈直到栈顶小于等于当前高度。
代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 using namespace std;
5 int st[250050],top,n,ans;
6 int main()
7 {
8 scanf("%d",&n);
9 int x,y;
10 for(int i=1;i<=n;i++)
11 {
12 scanf("%d%d",&y,&x);
13 if(top==0)
14 {
15 ans++;
16 st[top++]=x;continue;
17 }
18 if(x<=st[top-1])
19 {
20 while(top&&x<st[top-1])top--;
21 if(!top||x>st[top-1])ans++;
22 st[top++]=x;
23 }
24 else
25 {
26 ans++;
27 st[top++]=x;
28 }
29 }
30 printf("%d",ans);
31 }
[POI2005]SKA-Piggy Banks
题意:https://www.luogu.org/problemnew/show/P3420
分析:每个罐子向里面含有的钥匙连边,显然图中不会有复杂的环套环这种,考虑每个联通快,如果是环则对答案贡献为1,否则对答案贡献为入度为0的点的个数。
代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 using namespace std;
5 #define N 1000010
6 int n,fa[N],ans,c[N],f[N];
7 void read(int &x)
8 {
9 int f=1;x=0;char s=getchar();
10 while(s<\'0\'||s>\'9\'){if(s==\'-\')f=-1;s=getchar();}
11 while(s>=\'0\'&&s<=\'9\'){x=(x<<3)+(x<<1)+s-\'0\';s=getchar();}
12 x*=f;
13 }
14 int find(int x)
15 {
16 return fa[x]^x?fa[x]=find(fa[x]):x;
17 }
18 int main()
19 {
20 read(n);
21 register int i;
22 int x;
23 for(i=1;i<=n;++i)fa[i]=i;
24 for(i=1;i<=n;++i)
25 {
26 read(x);
27 int di=find(i),dx=find(x);
28 c[i]++;
29 fa[di]=dx;
30 }
31 for(i=1;i<=n;++i)
32 {
33 if(fa[i]==i)ans++;
34 }
35 for(i=1;i<=n;++i)
36 {
37 if(!c[i])
38 {
39 int di=find(i);
40 if(!f[di])f[di]=1;
41 else ans++;
42 }
43 }
44 printf("%d",ans);
45 }
[POI2008]STA-Station
题意:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大
分析:树形DP,换根时减去儿子的子树大小加上n-儿子的子树大小。
代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 using namespace std;
5 #define N 1000010
6 #define LL long long
7 int head[N],to[N<<1],nxt[N<<1],cnt,n;
8 int dep[N],fa[N],siz[N],ans;
9 LL sum[N],mx;
10 void read(int &x)
11 {
12 int f=1;x=0;char s=getchar();
13 while(s<\'0\'||s>\'9\'){if(s==\'-\')f=-1;s=getchar();}
14 while(s>=\'0\'&&s<=\'9\'){x=(x<<3)+(x<<1)+s-\'0\';s=getchar();}x*=f;
15 }
16 inline void add(int u,int v)
17 {
18 to[++cnt]=v;
19 nxt[cnt]=head[u];
20 head[u]=cnt;
21 }
22 void dfs(int x,int y)
23 {
24 siz[x]=1;
25 dep[x]=dep[y]+1;
26 sum[1]+=dep[x];
27 fa[x]=y;
28 register int i;
29 for(i=head[x];i;i=nxt[i])
30 {
31 if(to[i]==y)continue;
32 dfs(to[i],x);
33 siz[x]+=siz[to[i]];
34 }
35 }
36 void niu(int x)
37 {
38 register int i;
39 for(i=head[x];i;i=nxt[i])
40 {
41 if(to[i]==fa[x])continue;
42 sum[to[i]]=sum[x]-(siz[to[i]]-1)+(n-siz[to[i]]-1);
43 if(sum[to[i]]>mx)
44 {
45 ans=to[i];mx=sum[to[i]];
46 }
47 else if(sum[to[i]]==mx&&to[i]<ans)ans=to[i];
48 niu(to[i]);
49 }
50 }
51 int main()
52 {
53 read(n);
54 int x,y;
55 register int i;
56 for(i=1;i<n;++i)
57 {
58 read(x);read(y);
59 add(x,y);add(y,x);
60 }
61 dfs(1,0);
62 ans=1;
63 mx=sum[1];
64 niu(1);
65 printf("%d",ans);
66 }
[POI2008]BLO
题意:Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。
分析:如果这个点不是割点,答案为2*n-2,否则需要加上以割点子节点为根的节点个数和剩余节点互相的乘积之和。
代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <algorithm>
4 using namespace std;
5 #define N 100050
6 #define M 1000050
7 #define LL long long
8 int head[N],to[M],nxt[M],siz[N],n,m,cnt;
9 LL ans[N];
10 int dfn[N],low[N],tot,cur[N];
11 inline void add(int u,int v){
12 to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
13 to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;
14 }
15 void read(int &x){
16 int f=1;x=0;char s=getchar();
17 while(s<\'0\'||s>\'9\'){if(s==\'-\')f=-1;s=getchar();}
18 while(s>=\'0\'&&s<=\'9\'){x=(x<<3)+(x<<1)+s-\'0\';s=getchar();}x*=f;
19 }
20 void tarjan(int x){
21 dfn[x]=low[x]=++tot;siz[x]=1;
22 int sum=0,flg=0;
23 for(int i=head[x];i;i=nxt[i]){
24 if(!dfn[to[i]]){
25 tarjan(to[i]);
26 siz[x]+=siz[to[i]];
27 low[x]=min(low[x],low[to[i]]);
28 if(low[to[i]]>=dfn[x]){
29 flg++;
30 ans[x]+=1ll*siz[to[i]]*(n-siz[to[i]]);
31 sum+=siz[to[i]];
32 if(x!=1||flg>1){
33 cur[x]=1;
34 }
35 }
36 }
37 else low[x]=min(low[x],dfn[to[i]]);
38 }
39 if(cur[x]){
40 ans[x]+=1ll*(n-sum-1)*(sum+1)+(n-1);
41 }else ans[x]=2*(n-1);
42 }
43 int main(){
44 read(n),read(m);
45 int x,y;
46 for(int i=1;i<=m;i++){
47 read(x),read(y);
48 add(x,y);
49 }
50 tarjan(1);
51 for(int i=1;i<=n;i++){
52 printf("%lld\\n",ans[i]);
53 }
54 }
[POI2008]CLO
题意:Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度。
分析:对于每个连通块,能够满足条件当且仅当连通块中边数大于等于点数,即存在环,用并查集维护一下就行。
代码: