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 }
View Code

 

[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 }
View Code

 

[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 }
View Code

 

[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 }
View Code

 

[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 }
View Code

 

[POI2008]CLO

题意:Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度。

分析:对于每个连通块,能够满足条件当且仅当连通块中边数大于等于点数,即存在环,用并查集维护一下就行。

代码: