【UOJ Easy Round #1】

数论/Trie/并查集


猜数

  这题我是这样分析的……

  $a*b=g*l=n=k^2 \ and \ (g|a,g|b) \Rightarrow (g*a')*(g*b' )=g*l=k^2 \\ \Rightarrow a' * b' =\frac{l}{g}=(\frac{k}{g})^2  \Rightarrow min(a'+b')=2* \sqrt{\frac{l}{g}}, max(a'+b')=1+\frac{l}{g}$

  然而算ans的时候还需要再乘g……我给忘了

 1 //UOJ Easy Round1 A
 2 #include<vector>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define rep(i,n) for(int i=0;i<n;++i)
10 #define F(i,j,n) for(int i=j;i<=n;++i)
11 #define D(i,j,n) for(int i=j;i>=n;--i)
12 using namespace std;
13 typedef long long LL;
14 const int N=1e5+10;
15 /*******************template********************/
16 
17 LL n,g,l;
18 int main(){
19 #ifndef ONLINE_JUDGE
20     freopen("A.in","r",stdin);
21     freopen("A.out","w",stdout);
22 #endif 
23     int T; scanf("%d",&T);
24     while(T--){
25         scanf("%lld%lld",&g,&l);
26         printf("%lld %lld\n",2*(LL)sqrt(l/g)*g,l+g);
27     }
28     return 0;
29 }
View Code

跳蚤OS

  Trie树+go指针

  所以我们其实只要实现一个沿着Trie树和go指针走的Find函数就可以(找到该字符串在Trie中的实际位置)

  这里需要特判一下根目录,因为只有它一个是以'\'结尾的。

  这个……yy出来以后实现还是比较容易的。

  坑爹的是strlen函数是O(n)的,所以最好拿一个变量来保存这个值。(优化了一下,用时居然rank1了,真是令人感动)

 1 //UOJ Easy Round1 B
 2 #include<vector>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 using namespace std;
12 typedef long long LL;
13 inline int getint(){
14     int r=1,v=0; char ch=getchar();
15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
17     return r*v;
18 }
19 const int N=1e6+10;
20 /*******************template********************/
21 
22 int c[N][27],go[N],fa[N],n,m,tot=1;
23 char s1[N],s2[N],t[N];
24 inline int id(char ch){
25     if (ch=='/') return 26;
26     else return ch-'a';
27 }
28 int Find(char *s){
29     int x=1,y;
30     int l=strlen(s);
31     rep(i,l){
32         y=id(s[i]);
33         if (!c[x][y]){
34             c[x][y]=++tot;
35             fa[tot]=x;
36             t[tot]=s[i];
37         }
38         x=c[x][y];
39         if ((s[i+1]=='/'||i+1==l) && go[x]) x=go[x];
40     }
41     return x;
42 }
43 int main(){
44 #ifndef ONLINE_JUDGE
45     freopen("B.in","r",stdin);
46     freopen("B.out","w",stdout);
47 #endif 
48     scanf("%d%d",&n,&m);
49     F(i,1,n){
50         scanf("%s%s",s1,s2);
51         int t1=Find(s1),t2=Find(s2);
52         if (t2==2) t2=1;
53         go[t1]=t2;
54     }
55     F(i,1,m){
56         scanf("%s",s1);
57         int num=0;
58         for(int t1=Find(s1);t1!=1;t1=fa[t1])
59             s2[num++]=t[t1];
60         if (num==0) s2[num++]='/';
61         D(i,num-1,0) printf("%c",s2[i]); puts("");
62     }
63     return 0;
64 }
View Code

DZY Loves Graph

  离线模拟+并查集 按秩合并 按size合并

  Orz pyz5715

  虽然题解看懂了,但是并不会写……

  这里是用一个数组记录下来我们每插入一条边,当前的边权和,连通块个数(如果为1则成了一棵树,可以出解了),以及修改了谁的father。

  merge操作就是修改这三个东西……

  考虑Remove,也就是删掉一条边:

  如果最后一次加边并没有修改father,那么直接删就好了……cur--

  否则:我们要将这条边断掉,此时由于我们保存了该时刻的边权和以及连通块个数,所以这些都不用考虑修改……唯一需要重新维护的是每个并查集的rank,这里我一开始yy的修改方式是:将从x到其所在并查集的root的rank都减去rank[x]。然而这样TLE了……FST了最后一个点(非常鬼畜,加一条边,减一条边,加两条边,减两条边……)一开始我以为是需要卡常数,照着神犇的代码一点一点改……然而其实是这里出了问题:每次要将这一条链上的每个点 i 的rank[fa[i]]-=rank[i]。(目前百思不得其解,留一个坑吧)

这里我们离线做,做完一个操作后先读一下,看下下一个操作是不是Remove,如果是就直接执行。(这里我的感觉是为了方便知道要撤销的操作是什么)

UPD:2015年6月24日 09:06:56(Orz zyf)

  其实是由于循环条件写的是i!=fa[i],然后我每次修改的是rank[i]-=rank[x],所以会导致根那个点(i==fa[i])没有修改……改成每次修改rank[fa[i]]-=rank[x]就可以了

 1 //UOJ Easy Round1 C
 2 //orz pyz5715
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 #define pb push_back
12 using namespace std;
13 typedef long long LL;
14 inline int getint(){
15     int r=1,v=0; char ch=getchar();
16     for(;ch<'0' || ch>'9';ch=getchar()) if (ch=='-') r=-1;
17     for(;ch>='0' && ch<='9';ch=getchar()) v=(v<<3)+(v<<1)-'0'+ch;
18     return r*v;
19 }
20 const int N=500010;
21 /*******************template********************/
22 
23 int n,m,cur,p[N],fa[N],rank[N],size[N],x,y;
24 LL w[N];
25 char cmd;
26 
27 inline int getfa(int x){return fa[x]==x?x:getfa(fa[x]);}
28 
29 inline void Merge(int x,int y,int val){
30     x=getfa(x), y=getfa(y);
31     w[++cur]=w[cur-1]; p[cur]=0;
32     size[cur]=size[cur-1];
33     if (x==y) return;
34     if (rank[x]<rank[y]) swap(x,y);
35     fa[p[cur]=y]=x; rank[x]+=rank[y];
36     w[cur]+=val; --size[cur];
37 }
38 
39 inline void Remove(){
40     int x=p[cur--];
41     if (x){
42         for(int i=x;i!=fa[i];i=fa[i])
43             rank[fa[i]]-=rank[x];
44         fa[x]=x;
45     }
46 }
47 inline char getc(){
48     char ch;
49     while(ch=getchar(),ch<65 || ch>90);
50     return ch;
51 }
52 int main(){
53 #ifndef ONLINE_JUDGE
54     freopen("C.in","r",stdin);
55     freopen("C.out","w",stdout);
56 #endif
57     n=getint(); m=getint();
58     F(i,1,n) fa[i]=i,rank[i]=1;
59     size[0]=n;
60     cmd=getc();
61     F(i,1,m){
62         if (cmd=='A'){
63             x=getint(),y=getint();
64             Merge(x,y,i);
65             printf("%lld\n",size[cur]==1?w[cur]:0);
66             if (i!=m && (cmd=getc())=='R') Remove();
67         }else if (cmd=='D'){
68             x=getint();
69             printf("%lld\n",size[cur-x]==1?w[cur-x]:0);
70             if (i!=m && (cmd=getc())!='R') while(x--) Remove();
71         }else{
72             printf("%lld\n",size[cur]==1?w[cur]:0);
73             if (i!=m) cmd=getc();
74         }
75     }
76     return 0;
77 }
View Code

 

posted @ 2015-06-19 12:10  Tunix  阅读(259)  评论(0编辑  收藏  举报