POI2012

现在才开始写 POI 是不是太弱了?

-Rendezvous

怎么说呢,我发现我的代码好长啊~长啊~长啊~长长长长长长长长长长长长长长长长长长长长长长啊~

大概就是在一个内向树上搞一个类似 lca 的东西,想想内向树估计就可以搞出来了吧……

  1 #include <cstdio>
  2 const int sizeOfPoint=500005;
  3 const int sizeOfEdge=500005;
  4
  5 inline int lg(int);
  6 inline int min(int, int);
  7 inline int max(int, int);
  8 inline void swap(int & , int & );
  9 inline int getint();
 10 inline void putint(int);
 11
 12 struct edge {int point; edge * next;};
 13 edge memory[sizeOfEdge], * port=memory;
 14 inline edge * newedge(int, edge * );
 15
 16 struct node {int x, y; inline node(int=0, int=0);};
 17 inline bool operator < (node, node);
 18
 19 int n, m, k;
 20 int p[sizeOfPoint];
 21 edge * e[sizeOfPoint];
 22 int a[32][sizeOfPoint];
 23 int g[sizeOfPoint], s[sizeOfPoint];
 24 int f[sizeOfPoint], d[sizeOfPoint];
 25 int l[sizeOfPoint];
 26 bool v[sizeOfPoint], b[sizeOfPoint];
 27 inline void bfs(int);
 28 inline int lca(int, int);
 29
 30 int main()
 31 {
 32     n=getint(), k=getint();
 33     for (int i=1;i<=n;i++)
 34     {
 35         p[i]=getint();
 36         e[p[i]]=newedge(i, e[p[i]]);
 37     }
 38
 39     for (int i=1;i<=n;i++) if (!v[i])
 40     {
 41         int u=i;
 42         for ( ;!b[u];u=p[u]) b[u]=true;
 43
 44         ++m;
 45         for (int j=1;!l[u];j++, u=p[u])
 46         {
 47             g[u]=m;
 48             s[m]++;
 49             l[u]=j;
 50             bfs(u);
 51         }
 52     }
 53
 54     for (int i=1;i<=k;i++)
 55     {
 56         int a=getint(), b=getint();
 57
 58         if (g[f[a]]!=g[f[b]])
 59         {
 60             putint(-1), putchar(‘ ‘);
 61             putint(-1), putchar(‘\n‘);
 62         }
 63         else if (f[a]==f[b])
 64         {
 65             int c=lca(a, b);
 66             putint(d[a]-d[c]), putchar(‘ ‘);
 67             putint(d[b]-d[c]), putchar(‘\n‘);
 68         }
 69         else
 70         {
 71             int o=s[g[f[a]]];
 72             node ans1=node(d[a], d[b]), ans2=node(d[a], d[b]);
 73
 74             if (l[f[a]]<l[f[b]])
 75             {
 76                 ans1.x+=l[f[b]]-l[f[a]];
 77                 ans2.y+=o-(l[f[b]]-l[f[a]]);
 78             }
 79             else
 80             {
 81                 ans1.x+=o-(l[f[a]]-l[f[b]]);
 82                 ans2.y+=l[f[a]]-l[f[b]];
 83             }
 84
 85             if (ans1<ans2)
 86             {
 87                 putint(ans1.x), putchar(‘ ‘);
 88                 putint(ans1.y), putchar(‘\n‘);
 89             }
 90             else
 91             {
 92                 putint(ans2.x), putchar(‘ ‘);
 93                 putint(ans2.y), putchar(‘\n‘);
 94             }
 95         }
 96     }
 97
 98     return 0;
 99 }
100
101 inline int lg(int x)
102 {
103     return 31-__builtin_clz(x);
104 }
105 inline int min(int x, int y)
106 {
107     return x<y?x:y;
108 }
109 inline int max(int x, int y)
110 {
111     return x>y?x:y;
112 }
113 inline void swap(int & x, int & y)
114 {
115     int t=x; x=y; y=t;
116 }
117 inline int getint()
118 {
119     register int num=0;
120     register char ch;
121     do ch=getchar(); while (ch<‘0‘ || ch>‘9‘);
122     do num=num*10+ch-‘0‘, ch=getchar(); while (ch>=‘0‘ && ch<=‘9‘);
123     return num;
124 }
125 inline void putint(int num)
126 {
127     char stack[11];
128     register int top=0;
129     if (num==0) stack[top=1]=‘0‘;
130     if (num<0) putchar(‘-‘), num=-num;
131     for ( ;num;num/=10) stack[++top]=num%10+‘0‘;
132     for ( ;top;top--) putchar(stack[top]);
133 }
134
135 inline edge * newedge(int point, edge * next)
136 {
137     edge * ret=port++;
138     ret->point=point; ret->next=next;
139     return ret;
140 }
141
142 inline node::node(int _x, int _y)
143 {
144     x=_x;
145     y=_y;
146 }
147 inline bool operator < (node a, node b)
148 {
149     if (max(a.x, a.y)<max(b.x, b.y)) return true;
150     if (max(a.x, a.y)>max(b.x, b.y)) return false;
151     if (min(a.x, a.y)<min(b.x, b.y)) return true;
152     if (min(a.x, a.y)>min(b.x, b.y)) return false;
153     return a.y<b.y;
154 }
155
156 inline void bfs(int root)
157 {
158     static int q[sizeOfPoint];
159     int s=0, t=0;
160     d[root]=0;
161     f[root]=root;
162
163     for (q[t++]=root;s<t;s++)
164     {
165         int u=q[s];
166         v[u]=true;
167         if (d[u]>1)
168         {
169             int lim=lg(d[u]);
170             for (int i=1;i<=lim;i++)
171                 a[i][u]=a[i-1][a[i-1][u]];
172         }
173
174         for (edge * i=e[u];i;i=i->next) if (i->point!=p[u] && !l[i->point])
175         {
176             d[i->point]=d[u]+1;
177             f[i->point]=root;
178             a[0][i->point]=u;
179             q[t++]=i->point;
180         }
181     }
182 }
183 inline int lca(int u, int v)
184 {
185     int dist;
186     if (d[u]<d[v]) swap(u, v);
187     while ((dist=d[u]-d[v])) u=a[__builtin_ctz(dist)][u];
188     if (u==v) return u;
189     for (int i=31;i>=0;i--)
190         if (a[i][u]!=a[i][v])
191             u=a[i][u],
192             v=a[i][v];
193     return a[0][u];
194 }

LEN:190+

时间: 2024-10-06 21:55:50

POI2012的相关文章

Bzoj 2789: [Poi2012]Letters 树状数组,逆序对

2789: [Poi2012]Letters Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 278  Solved: 185[Submit][Status][Discuss] Description 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. Input 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度

[BZOJ2797][Poi2012]Squarks

2797: [Poi2012]Squarks Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 211  Solved: 89[Submit][Status][Discuss] Description 设有n个互不相同的正整数{X1,X2,...Xn},任取两个Xi,Xj(i≠j),能算出Xi+Xj.现在所有取法共n*(n-1)/2个和,要你求出X1,X2,...Xn. Input 第一行一个正整数n (3<=n<=300).第二行n*(n-1)/2

[BZOJ2791][Poi2012]Rendezvous

2791: [Poi2012]Rendezvous Time Limit: 25 Sec  Memory Limit: 128 MBSubmit: 95  Solved: 71[Submit][Status][Discuss] Description 给定一个n个顶点的有向图,每个顶点有且仅有一条出边.对于顶点i,记它的出边为(i, a[i]).再给出q组询问,每组询问由两个顶点a.b组成,要求输出满足下面条件的x.y:1. 从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同.2.

[BZOJ2793][Poi2012]Vouchers

2793: [Poi2012]Vouchers Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 316  Solved: 148[Submit][Status][Discuss] Description 考虑正整数集合,现在有n组人依次来取数,假设第i组来了x人,他们每个取的数一定是x的倍数,并且是还剩下的最小的x个.正整数中有m个数被标成了幸运数,问有哪些人取到了幸运数. Input 第一行一个正整数m (m<=1,000,000),下面m行每行一

[BZOJ2795][Poi2012]A Horrible Poem

2795: [Poi2012]A Horrible Poem Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 261  Solved: 150[Submit][Status][Discuss] Description 给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节.如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到. Input 第一行一个正整数n (n<=500,000),表示S的长度.第二行n个小

[BZOJ2792][Poi2012]Well

2792: [Poi2012]Well Time Limit: 40 Sec  Memory Limit: 64 MBSubmit: 137  Solved: 61[Submit][Status][Discuss] Description 给出n个正整数X1,X2,...Xn,可以进行不超过m次操作,每次操作选择一个非零的Xi,并将它减一. 最终要求存在某个k满足Xk=0,并且z=max{|Xi - Xi+1|}最小. 输出最小的z和此时最小的k. Input 第一行两个正整数n, m (1<=

[BZOJ2788][Poi2012]Festival

2788: [Poi2012]Festival Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 187  Solved: 91[Submit][Status][Discuss] Description 有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类: 1. 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb 2. 给出c,d (1<=c,d<=n),要求满足Xc <= Xd 在满足所

[BZOJ2790][Poi2012]Distance

2790: [Poi2012]Distance Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 225  Solved: 115[Submit][Status][Discuss] Description 对于两个正整数a.b,这样定义函数d(a,b):每次操作可以选择一个质数p,将a变成a*p或a/p, 如果选择变成a/p就要保证p是a的约数,d(a,b)表示将a变成b所需的最少操作次数.例如d(69,42)=3. 现在给出n个正整数A1,A2,.

2795: [Poi2012]A Horrible Poem

2795: [Poi2012]A Horrible Poem Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 484  Solved: 235[Submit][Status][Discuss] Description 给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节.如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到. Input 第一行一个正整数n (n<=500,000),表示S的长度.第二行n个小

【BZOJ2789】[Poi2012]Letters 树状数组

[BZOJ2789][Poi2012]Letters Description 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. Input 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度. 第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母. Output 一个非负整数,表示最少的交换次数. Sample Input 3 ABC BCA Samp