数据结构整理
今天实在是太颓了……前几天把自己认为的可做题写完了,现在刷题列表里只剩下了一些自己不(xia)愿(ji)意(ba)写(zhao)的毒瘤题了,实在不愿意做……
于是整个上午睡觉,然后发现自己连水题都不愿意写了……
还是来整理一下这些天写过的题目吧……
Bzoj3123:
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=3123
首先这题如果不强制在线,我们把这棵树建出来然后主席树乱搞一下就好了(皮这一下很开心吗?)
然后考虑在线怎么做,我们可以按秩合并,也就多一个log罢了,于是我们得到了一个优秀的nlog^2n做法:每次把较小的联通块的主席树扔掉,然后重建即可。
其余的细节?就是顺便用倍增维护一下LCA,用并查集维护一下联通块size就好了。
关于GC(垃圾回收):我写的有0号点作为空树的主席树是没法GC的,只能二分数组大小然后卡过。这个我也问过梁大爷,如果不用0号树,直接用0号点做所有空节点的话,是可以GC的。话说这题时限本来就卡,写了GC不就是TLE(雾)。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=8e4+1e2,maxl=20; 8 9 struct ChairmanTree { 10 int l[maxn*200],r[maxn*200],lson[maxn*200],rson[maxn*200],sum[maxn*200],cnt; 11 inline int NewNode() { 12 return ++cnt; 13 } 14 inline void build(int pos,int ll,int rr) { 15 l[pos] = ll , r[pos] = rr; 16 if( ll == rr ) return; 17 const int mid = ( ll + rr ) >> 1; 18 build(lson[pos]=NewNode(),ll,mid); 19 build(rson[pos]=NewNode(),mid+1,rr); 20 } 21 inline void insert(int pos,int pre,int x) { 22 l[pos] = l[pre] , r[pos] = r[pre] , 23 lson[pos] = lson[pre] , rson[pos] = rson[pre]; 24 if( l[pos] == r[pos] ) { 25 sum[pos] = sum[pre] + 1; 26 return; 27 } const int mid = ( l[pos] + r[pos] ) >> 1; 28 if( x <= mid ) insert(lson[pos]=NewNode(),lson[pre],x); 29 else insert(rson[pos]=NewNode(),rson[pre],x); 30 sum[pos] = sum[lson[pos]] + sum[rson[pos]]; 31 } 32 inline int cl(int a1,int a2,int b1,int b2) { 33 return sum[lson[a1]] + sum[lson[a2]] - sum[lson[b1]] - sum[lson[b2]]; 34 } 35 inline int query(int a1,int a2,int b1,int b2,int k) { 36 if( l[a1] == r[a1] ) return l[a1]; 37 int sl = cl(a1,a2,b1,b2); 38 if( k <= sl ) return query(lson[a1],lson[a2],lson[b1],lson[b2],k); 39 return query(rson[a1],rson[a2],rson[b1],rson[b2],k-sl); 40 } 41 }tr; 42 struct UnionFindSet { 43 int fa[maxn],siz[maxn]; 44 inline int findfa(int x) { 45 if( fa[x] == x ) return x; 46 siz[fa[x]] += siz[x] , siz[x] = 0; 47 return fa[x] = findfa(fa[x]); 48 } 49 inline int getsiz(int x) { 50 return siz[findfa(x)]; 51 } 52 inline void merge(int x,int y) { 53 x = findfa(x) , y = findfa(y); 54 siz[x] += siz[y] , siz[y] = 0; 55 fa[y] = x; 56 } 57 inline void init(int n) { 58 for(int i=1;i<=n;i++) fa[i] = i , siz[i] = 1; 59 } 60 }ufs; 61 62 int in[maxn],srt[maxn],slen; 63 int s[maxn],t[maxn<<2],nxt[maxn<<2],cnt; 64 int fa[maxn][maxl],root[maxn],dep[maxn]; 65 int n; 66 67 inline void addedge(int from,int to) { 68 t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt; 69 } 70 inline void recycle(int pos) { 71 for(int at=s[pos];at;at=nxt[at]) 72 if( t[at] != fa[pos][0] ) 73 recycle(t[at]); 74 memset(fa[pos],0,sizeof(fa[pos])); 75 } 76 inline void build(int pos) { 77 root[pos] = tr.NewNode(); 78 tr.insert(root[pos],root[fa[pos][0]],in[pos]); 79 for(int i=1;i<maxl;i++) fa[pos][i] = fa[fa[pos][i-1]][i-1]; 80 for(int at=s[pos];at;at=nxt[at]) 81 if( t[at] != fa[pos][0] ) { 82 fa[t[at]][0] = pos , dep[t[at]] = dep[pos] + 1; 83 build(t[at]); 84 } 85 } 86 inline int lca(int x,int y) { 87 if( dep[x] < dep[y] ) swap(x,y); 88 for(int i=maxl-1;~i;i--) 89 if( dep[x] - dep[y] >= ( 1 << i ) ) 90 x = fa[x][i]; 91 if( x == y ) return x; 92 for(int i=maxl-1;~i;i--) 93 if( fa[x][i] != fa[y][i] ) 94 x = fa[x][i] , y = fa[y][i]; 95 return fa[x][0]; 96 } 97 inline int getroot(int x) { 98 for(int i=maxl-1;~i;i--) 99 if( fa[x][i] ) 100 x = fa[x][i]; 101 return x; 102 } 103 inline int kth(int x,int y,int k) { 104 int l = lca(x,y) , f = fa[l][0]; 105 return tr.query(root[x],root[y],root[l],root[f],k); 106 } 107 inline void merge(int x,int y) { 108 int sx = ufs.getsiz(x) , sy = ufs.getsiz(y); 109 if( sx < sy ) swap(x,y); 110 recycle(getroot(y)); 111 ufs.merge(x,y); 112 addedge(x,y) , addedge(y,x); 113 fa[y][0] = x , dep[y] = dep[x] + 1; 114 build(y); 115 } 116 117 inline void init() { 118 memcpy(srt+1,in+1,sizeof(int)*n); 119 sort(srt+1,srt+1+n) , slen = unique(srt+1,srt+1+n) - srt - 1; 120 for(int i=1;i<=n;i++) in[i] = lower_bound(srt+1,srt+1+slen,in[i]) - srt; 121 root[0] = tr.NewNode(); 122 tr.build(root[0],1,slen); 123 ufs.init(n); 124 for(int i=1;i<=n;i++) 125 if( !root[i] ) build(i); 126 for(int i=1;i<=n;i++) 127 if( fa[i][0] ) ufs.merge(fa[i][0],i); 128 } 129 130 int main() { 131 static int m,os,la; 132 static char o[10]; 133 scanf("%*d%d%d%d",&n,&m,&os) , la = 0; 134 for(int i=1;i<=n;i++) scanf("%d",in+i); 135 for(int i=1,a,b;i<=m;i++) { 136 scanf("%d%d",&a,&b); 137 addedge(a,b) , addedge(b,a); 138 } 139 init(); 140 for(int i=1,x,y,k;i<=os;i++) { 141 scanf("%s%d%d",o,&x,&y) , x ^= la , y ^= la; 142 if( *o == 'Q' ) { 143 scanf("%d",&k) , k ^= la; 144 la = kth(x,y,k); 145 la = srt[la]; 146 printf("%d\n",la); 147 } else { 148 merge(x,y); 149 } 150 } 151 return 0; 152 }
Bzoj1453:
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=1453
各位大佬看来这不是LCT水题吗?或者cdq+并查集乱搞一下。
然而为什么我一开始想到的是n^2m的暴力?
考虑暴力怎么优化?如果我们把一维建成线段树,另一位继续暴力,是不是就能卡过去了呢?
我们在线段树的每个节点上维护区间左边一列位置,右边一列位置,左边一列的id,右边一列的id,每个id是否出现在左、右,区间内的黑色、白色联通块数,然后合并一下就可以了。
关于这玩意怎么合并?我们考虑用并查集维护每个格子属于哪个集合。我们先把右区间的id全部加400的偏移量,然后让左区间的右和右区间的左去合并。合并完成后统计合并失败后被封锁(无法接触左右边界)的黑白联通块数并更新答案,然后重新离散化id并维护每个id在左右是否出现了。
这题复杂度不怎么卡,常数写的很丑也给过了QAQ。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=2e2+1e1,maxl=8e2+1e1; 6 7 int in[maxn][maxn],tp[maxl]; 8 int n; 9 10 struct UnionFindSet { 11 int fa[maxl]; 12 inline int findfa(int x) { 13 return fa[x] == x ? x : fa[x] = findfa(fa[x]); 14 } 15 inline void merge(int x,int y) { 16 x = findfa(x) , y = findfa(y); 17 if( x != y ) fa[x] = y; 18 } 19 inline void resfa(int k) { 20 for(int i=1;i<=k;i++) fa[i] = i; 21 } 22 }ufs; 23 24 struct Node { 25 int fal[maxn],far[maxn],sta[maxn<<1],l,r,inb,inw; // sta means a number's appear place . 26 Node() { 27 memset(fal,0,sizeof(fal)); 28 memset(far,0,sizeof(far)); 29 memset(sta,0,sizeof(sta)); 30 l = r = inb = inw = 0; 31 } 32 inline void rebuild() { 33 static int cov[maxl] , cnt; 34 memset(cov,0,sizeof(cov)) , cnt = 0; 35 for(int i=1;i<=n;i++) if( !cov[fal[i]] ) cov[fal[i]] = ++cnt; 36 for(int i=1;i<=n;i++) if( !cov[far[i]] ) cov[far[i]] = ++cnt; 37 for(int i=1;i<=n;i++) fal[i] = cov[fal[i]] , sta[fal[i]] |= 1; // 1 means appeared on left . 38 for(int i=1;i<=n;i++) far[i] = cov[far[i]] , sta[far[i]] |= 2; // 2 means appeared on right . 39 } 40 inline void getfa() { 41 for(int i=1;i<=n;i++) fal[i] = ufs.findfa(fal[i]) , far[i] = ufs.findfa(far[i]); 42 } 43 friend Node operator + (const Node &a,const Node &fakeb) { // we have to operate b. 44 Node ret,b=fakeb; 45 ret.l = a.l , ret.r = b.r , ret.inb = a.inb + b.inb , ret.inw = a.inw + b.inw; 46 int mil = a.r , mir = b.l; 47 ufs.resfa(n<<2) , memset(tp,0,sizeof(tp)); 48 for(int i=1;i<=n;i++) 49 b.fal[i] += n<<1 , b.far[i] += n<<1; 50 memcpy(ret.fal,a.fal,sizeof(a.fal)) , memcpy(ret.far,b.far,sizeof(b.far)); 51 for(int i=1;i<=n;i++) 52 if( in[i][mil] == in[i][mir] ) ufs.merge(a.far[i],b.fal[i]); 53 for(int i=1;i<=n;i++) 54 tp[ufs.findfa(ret.fal[i])] |= 1 , tp[ufs.findfa(ret.far[i])] |= 2; 55 for(int i=1;i<=n;i++) { 56 if( !tp[ufs.findfa(a.far[i])] ) { 57 tp[ufs.findfa(a.far[i])] = 4; 58 if( in[i][mil] == 0 ) ++ret.inw; 59 else ++ret.inb; 60 } 61 if( !tp[ufs.findfa(b.fal[i])] ) { 62 tp[ufs.findfa(b.fal[i])] = 4; 63 if( in[i][mir] == 0 ) ++ret.inw; 64 else ++ret.inb; 65 } 66 } 67 ret.getfa() , ret.rebuild(); 68 return ret; 69 } 70 inline void set(int p) { 71 l = r = p , inb = inw = 0; 72 int c = 0; 73 for(int i=1;i<=n;i++) { 74 if( i == 1 || in[i][p] != in[i-1][p] ) fal[i] = far[i] = ++c , sta[c] = 3; 75 else fal[i] = far[i] = fal[i-1]; 76 } 77 } 78 inline void count(int& retb,int& retw) { 79 static bool vis[maxn<<1]; 80 memset(vis,0,sizeof(vis)); 81 retb = inb , retw = inw; 82 for(int i=1;i<=n;i++) 83 if( !vis[fal[i]] ) { 84 vis[fal[i]] = 1; 85 if( in[i][l] == 0 ) ++retw; 86 else ++retb; 87 } 88 for(int i=1;i<=n;i++) 89 if( !vis[far[i]] ) { 90 vis[far[i]] = 1; 91 if( in[i][r] == 0 ) ++retw; 92 else ++retb; 93 } 94 } 95 }ns[maxn<<3]; 96 97 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],cnt; 98 99 inline void build(int pos,int ll,int rr) { 100 l[pos] = ll , r[pos] = rr; 101 if( ll == rr ) { 102 ns[pos].set(ll); 103 return; 104 } const int mid = ( ll + rr ) >> 1; 105 build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+1,rr); 106 ns[pos] = ns[lson[pos]] + ns[rson[pos]]; 107 } 108 inline void update(int pos,int tar) { 109 if( tar < l[pos] || r[pos] < tar ) return; 110 if( l[pos] == r[pos] ) { 111 ns[pos].set(l[pos]); 112 return; 113 } 114 update(lson[pos],tar) , update(rson[pos],tar); 115 ns[pos] = ns[lson[pos]] + ns[rson[pos]]; 116 } 117 118 inline void printans() { 119 static int ab,aw; 120 ns[1].count(ab,aw); 121 printf("%d %d\n",ab,aw); 122 } 123 int main() { 124 static int m; 125 scanf("%d",&n); 126 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",in[i]+j); 127 build(cnt=1,1,n); 128 scanf("%d",&m); 129 for(int i=1,x,y;i<=m;i++) { 130 scanf("%d%d",&x,&y); 131 in[x][y] = !in[x][y]; 132 update(1,y); 133 printans(); 134 } 135 return 0; 136 }
Bzoj3796:
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=3786
这真不是LCT水题?等等,子树加,LCT做不了。
考虑用DFS序解决子树加的问题,关于子树加,就是区间加。关于更换父亲?就是区间移动喽。
对于区间移动,就是先提取区间,然后把他放到新的父亲的右边的第一个位置即可。
如果你懒得加哨兵节点,代码细节较多注意讨论。
代码:
1 2 #pragma GCC optimize(3) 3 #include<cstdio> 4 #include<cctype> 5 #define lli long long int 6 const int maxn=2e5+1e2; 7 8 int st,ed; 9 10 struct Splay { 11 int ch[maxn][2],fa[maxn],tpe[maxn],siz[maxn],cnt,root; 12 lli sum[maxn],dat[maxn],lazy[maxn]; 13 14 inline void set(int pos,lli add) { 15 if( !pos ) return; 16 dat[pos] += tpe[pos] * add , sum[pos] += siz[pos] * add , lazy[pos] += add; 17 } 18 inline void push(int pos) { 19 if( !lazy[pos] ) return; 20 set(ch[pos][0],lazy[pos]) , 21 set(ch[pos][1],lazy[pos]) , 22 lazy[pos] = 0; 23 } 24 inline void up(int fa,int son) { 25 if( !son ) return; 26 siz[fa] += siz[son] , sum[fa] += sum[son]; 27 } 28 inline void upgrade(int pos) { 29 siz[pos] = tpe[pos] , sum[pos] = dat[pos]; 30 up(pos,ch[pos][0]) , 31 up(pos,ch[pos][1]) ; 32 } 33 inline int gid(int x) { 34 return x == ch[fa[x]][1]; 35 } 36 inline void rotate(int x) { 37 const int f = fa[x] , id = gid(x); 38 push(f) , push(x); 39 fa[x] = fa[f]; 40 if( fa[f] ) ch[fa[f]][gid(f)] = x; 41 else root = x; 42 ch[f][id] = ch[x][id^1]; 43 if( ch[x][id^1] ) fa[ch[x][id^1]] = f; 44 ch[x][id^1] = f , fa[f] = x; 45 upgrade(f) , upgrade(x); 46 } 47 inline void splay(int pos) { 48 while( pos != root ) { 49 if( fa[fa[pos]] ) rotate(fa[pos]); 50 rotate(pos); 51 } 52 } 53 inline void upchain(int pos) { 54 while( pos != root ) { 55 upgrade(pos) , pos = fa[pos]; 56 } 57 } 58 inline int insert(int tp,int va) { 59 if( !root ) { 60 root = ++cnt , tpe[root] = tp , sum[root] = dat[root] = tp * va; 61 return root; 62 } 63 int ret = ++cnt , now = root; 64 tpe[ret] = tp , sum[ret] = dat[ret] = tp * va; 65 while( ch[now][1] ) now = ch[now][1]; 66 ch[now][1] = ret , fa[ret] = now; 67 upchain(ret); 68 splay(ret); 69 return ret; 70 } 71 inline void mkrson(int pos) { 72 while( pos != ch[root][1] ) { 73 if( fa[pos] != ch[root][1] ) rotate(fa[pos]); 74 rotate(pos); 75 } 76 } 77 inline void pushchain(int pos) { 78 if( pos != root ) pushchain(fa[pos]); 79 push(pos); 80 } 81 inline int getprv(int pos) { 82 if( pos == st ) return -1; 83 if( ch[pos][0] ) { 84 int ret = ch[pos][0]; 85 while( ch[ret][1] ) ret = ch[ret][1]; 86 return ret; 87 } 88 while( pos == ch[fa[pos]][0] ) pos = fa[pos]; 89 return fa[pos]; 90 } 91 inline int getnxt(int pos) { 92 if( pos == ed ) return -1; 93 if( ch[pos][1] ) { 94 int ret = ch[pos][1]; 95 while( ch[ret][0] ) ret = ch[ret][0]; 96 return ret; 97 } 98 while( pos == ch[fa[pos]][1] ) pos = fa[pos]; 99 return fa[pos]; 100 } 101 inline void update(int posl,int posr,lli add) { 102 int prv = getprv(posl) , nxt = getnxt(posr); 103 if( !~prv && !~nxt ) { 104 set(root,add); 105 return; 106 } 107 splay(prv) , mkrson(nxt); 108 int pos = ch[ch[root][1]][0]; 109 set(pos,add); 110 splay(pos); 111 } 112 inline int segment(int posl,int posr) { // assert posl != in[1] && posr != out[1] . 113 int prv = getprv(posl) , nxt = getnxt(posr); 114 splay(prv) , mkrson(nxt); 115 return ch[ch[root][1]][0]; 116 } 117 inline void move(int posl,int posr,int nfa) { 118 int pos = segment(posl,posr); 119 pushchain(fa[pos]); 120 ch[fa[pos]][gid(pos)] = 0 , fa[pos] = 0; 121 splay(nfa); 122 int tar = ch[nfa][1]; 123 while( ch[tar][0] ) tar = ch[tar][0]; 124 pushchain(tar); 125 ch[tar][0] = pos , fa[pos] = tar; 126 splay(pos); 127 } 128 inline lli query(int pos) { 129 int nxt = getnxt(pos); 130 splay(nxt); 131 return sum[ch[root][0]]; 132 } 133 }T; 134 135 int s[maxn>>1],t[maxn],nxt[maxn]; 136 int in[maxn>>1],out[maxn>>1]; 137 int w[maxn>>1]; 138 139 inline void addedge(int from,int to) { 140 static int cnt = 0; 141 t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt; 142 } 143 inline void dfs(int pos) { 144 in[pos] = T.insert(1,w[pos]); 145 for(int at=s[pos];at;at=nxt[at]) 146 dfs(t[at]); 147 out[pos] = T.insert(-1,w[pos]); 148 } 149 150 inline char nextchar() { 151 const static int BS = 1 << 21; 152 static char buf[BS],*st=buf+BS,*ed=buf+BS; 153 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 154 return st == ed ? -1 : *st++; 155 } 156 inline int getint() { 157 int ret = 0 , ch; 158 while( !isdigit(ch=nextchar()) ); 159 do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) ); 160 return ret; 161 } 162 inline char realchar() { 163 char ret; 164 while( !isalpha(ret=nextchar()) ) ; 165 return ret; 166 } 167 int main() { 168 static int n,m; 169 static char o; 170 n = getint(); 171 for(int i=2,f;i<=n;i++) { 172 f = getint(); 173 addedge(f,i); 174 } 175 for(int i=1;i<=n;i++) w[i] = getint(); 176 dfs(1) , st = in[1] , ed = out[1]; 177 m = getint(); 178 for(int i=1,p,x;i<=m;i++) { 179 o = realchar() , p = getint(); 180 if( o == 'Q' ) printf("%lld\n",T.query(in[p])); 181 else { 182 x = getint(); 183 if( o == 'F' ) T.update(in[p],out[p],x); 184 else T.move(in[p],out[p],in[x]); 185 } 186 } 187 return 0; 188 }
Bzoj1493:
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=1493
前两个操作可以写用变量维护,然后线段树可做,细节较多。
好的,细节太多?我选择splay。
Rotate就是把区间最后一段移动到最前,Filp就是把区间[2,n]翻转。
然后swap看做两个单点的区间染色,我们只需要实现区间染色,统计区间颜色数量就可以了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=5e5+1e2; 6 7 int n; 8 9 struct Splay { 10 int ch[maxn][2],fa[maxn],col[maxn][2],dat[maxn],sum[maxn],siz[maxn],root,cnt; // sum includes color on sides . 11 int rev[maxn],recol[maxn]; // rev >= recol , so you must push recol first before pusing rev . 12 13 Splay() { 14 memset(recol,-1,sizeof(recol)); 15 } 16 inline void fill(int pos,int cc) { 17 if( !pos ) return; 18 col[pos][0] = col[pos][1] = dat[pos] = recol[pos] = cc , sum[pos] = 1; 19 } 20 inline void initfill(int pos,int cc) { 21 col[pos][0] = col[pos][1] = dat[pos] = cc , sum[pos] = 1; 22 } 23 inline void applyrev(int pos) { 24 if( !pos ) return; 25 swap( ch[pos][0] , ch[pos][1] ) , swap( col[pos][0] , col[pos][1] ); 26 } 27 inline void push(int pos) { 28 if( ~recol[pos] ) { 29 fill(ch[pos][0],recol[pos]) , fill(ch[pos][1],recol[pos]); 30 recol[pos] = -1; 31 } 32 if( rev[pos] ) { 33 rev[ch[pos][0]] ^= 1 , rev[ch[pos][1]] ^= 1; 34 applyrev(ch[pos][0]) , applyrev(ch[pos][1]); 35 rev[pos] = 0; 36 } 37 } 38 inline void upgrade(int pos) { 39 col[pos][0] = col[pos][1] = dat[pos] , sum[pos] = 1 , 40 siz[pos] = 1; 41 if( ch[pos][0] ) { 42 sum[pos] = sum[pos] + sum[ch[pos][0]] - ( col[ch[pos][0]][1] == col[pos][0] ) , 43 col[pos][0] = col[ch[pos][0]][0] , 44 siz[pos] += siz[ch[pos][0]] ; 45 } 46 if( ch[pos][1] ) { 47 sum[pos] = sum[pos] + sum[ch[pos][1]] - ( col[pos][1] == col[ch[pos][1]][0] ) , 48 col[pos][1] = col[ch[pos][1]][1] , 49 siz[pos] += siz[ch[pos][1]] ; 50 } 51 } 52 inline int gid(int x) { 53 return x == ch[fa[x]][1]; 54 } 55 inline void rotate(int x) { 56 push(fa[x]) , push(x); 57 const int f = fa[x] , id = gid(x); 58 fa[x] = fa[f]; 59 if( fa[f] ) ch[fa[f]][gid(f)] = x; 60 else root = x; 61 ch[f][id] = ch[x][id^1]; 62 if( ch[x][id^1] ) fa[ch[x][id^1]] = f; 63 ch[x][id^1] = f , fa[f] = x; 64 upgrade(f) , upgrade(x); 65 } 66 inline void splay(int pos) { 67 while( root != pos ) { 68 if( fa[fa[pos]] ) rotate(fa[pos]); 69 rotate(pos); 70 } 71 } 72 inline void upchain(int x) { 73 while( x ) { 74 upgrade(x) , 75 x = fa[x]; 76 } 77 } 78 inline void pushchain(int x) { 79 if( fa[x] ) pushchain(fa[x]); 80 push(x); 81 } 82 inline void insert(int cc) { 83 if( !root ) { 84 root = ++cnt , siz[cnt] = 1; 85 initfill(root,cc); 86 return; 87 } 88 int now = root; 89 while( push(now) , ch[now][1] ) now = ch[now][1]; 90 ch[now][1] = ++cnt , siz[cnt] = 1 , fa[cnt] = now; 91 initfill(cnt,cc) , upchain(cnt); 92 splay(cnt); 93 } 94 inline int kth(int k) { 95 int now = root; 96 while( 1 ) { 97 push(now); 98 if( k < 0 ) exit(0); 99 if( k == siz[ch[now][0]] + 1 ) return now; 100 if( k <= siz[ch[now][0]] ) now = ch[now][0]; 101 else k -= siz[ch[now][0]] + 1 , now = ch[now][1]; 102 } 103 throw "It Shouldn't Be Here ." ; 104 } 105 inline void insertleft(int pos) { 106 int now = root; 107 while( push(now) , ch[now][0] ) now = ch[now][0]; 108 ch[now][0] = pos , fa[pos] = now; 109 upchain(now); 110 } 111 inline void move(int k) { 112 int mip = kth(n-k); 113 splay(mip) , pushchain(mip); 114 int pos = ch[mip][1]; ch[mip][1] = fa[pos] = 0; 115 upchain(mip); 116 insertleft(pos); 117 splay(pos); 118 } 119 inline void filp() { 120 int tar = kth(1); 121 splay(tar); 122 rev[ch[tar][1]] ^= 1 , applyrev(ch[tar][1]); 123 splay(ch[tar][1]); 124 } 125 inline int getp(int k) { 126 int pos = kth(k); 127 return dat[pos]; 128 } 129 inline void mkrson(int pos) { 130 while( pos != ch[root][1] ) { 131 if( fa[pos] != ch[root][1] ) rotate(fa[pos]); 132 rotate(pos); 133 } 134 } 135 inline void print(int st,int ed,int cc) { 136 if( st == 1 && ed == n ) { 137 fill(root,cc); 138 } else if( st == 1 ) { 139 int nxt = kth(ed+1); 140 splay(nxt); 141 fill(ch[root][0],cc); 142 splay(ch[root][0]); 143 } else if( ed == n ) { 144 int prv = kth(st-1); 145 splay(prv); 146 fill(ch[root][1],cc); 147 splay(ch[root][1]); 148 } else { 149 int nxt = kth(ed+1) , prv = kth(st-1); 150 splay(prv) , mkrson(nxt); 151 fill(ch[ch[root][1]][0],cc); 152 splay(ch[ch[root][1]][0]); 153 } 154 } 155 inline int count(int st,int ed) { 156 if( st == 1 && ed == n ) { 157 return max ( sum[root] - ( col[root][0] == col[root][1] ) , 1 ); 158 } else if( st == 1 ) { 159 int nxt = kth(ed+1); 160 splay(nxt); 161 return sum[ch[root][0]]; 162 } else if( ed == n ) { 163 int prv = kth(st-1); 164 splay(prv); 165 return sum[ch[root][1]]; 166 } else { 167 int nxt = kth(ed+1) , prv = kth(st-1); 168 splay(prv) , mkrson(nxt); 169 return sum[ch[ch[root][1]][0]]; 170 } 171 } 172 inline int count(int st,int ed,int& rc) { 173 if( st == 1 ) { 174 int nxt = kth(ed+1); 175 splay(nxt) , rc = col[ch[root][0]][0]; 176 return sum[ch[root][0]]; 177 } else if( ed == n ) { 178 int prv = kth(st-1); 179 splay(prv) , rc = col[ch[root][1]][1]; 180 return sum[ch[root][1]]; 181 } 182 throw "It Shouldn't Be Here ." ; 183 } 184 }T; 185 186 int main() { 187 static int m; 188 static char o[10]; 189 scanf("%d%*d",&n); 190 for(int i=1,x;i<=n;i++) { 191 scanf("%d",&x); 192 T.insert(x); 193 } 194 195 scanf("%d",&m); 196 for(int i=1,x,y,k;i<=m;i++) { 197 scanf("%s",o); 198 if( *o == 'F' ) T.filp(); 199 else if( *o == 'C' ) { 200 if( o[1] != 'S' ) printf("%d\n",T.count(1,n)); 201 else { 202 scanf("%d%d",&x,&y); 203 if( x <= y ) printf("%d\n",T.count(x,y)); 204 else { 205 int cx,cy,ans; 206 ans = T.count(x,n,cx) + T.count(1,y,cy); 207 ans -= ( cx == cy ); 208 printf("%d\n",ans); 209 } 210 } 211 } else { 212 if( *o == 'R' ) { 213 scanf("%d",&k); 214 T.move(k); 215 } else { 216 scanf("%d%d",&x,&y); 217 if( *o == 'S' ) { 218 int cx = T.getp(x) , cy = T.getp(y); 219 T.print(x,x,cy) , T.print(y,y,cx); 220 } else { 221 scanf("%d",&k); 222 if( x <= y ) T.print(x,y,k); 223 else T.print(x,n,k) , T.print(1,y,k); 224 } 225 } 226 } 227 } 228 return 0; 229 }
Bzoj2594:
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=2594
把自始至终一直存在的边先求最小生成树放进去,我们倒序考虑,就是不断加边维护最小生成树了。
LCT没法维护边权,拆边为点,维护点权就好了。
写太丑会T,叫你写快读你非得scanf。
代码:
1 #pragma GCC optimize(2) 2 #include<cstdio> 3 #include<algorithm> 4 #include<cctype> 5 const int maxn=1e5+1e2,maxm=1e6+1e2,maxp=1.2e6+1e2; 6 7 int n,m,q; 8 struct LCT { 9 int ch[maxp][2],fa[maxp],v[maxp],mx[maxp],rev[maxp]; 10 11 inline void applyrev(int pos) { 12 if( !pos ) return; 13 rev[pos] ^= 1 , 14 std::swap(ch[pos][0],ch[pos][1]); 15 } 16 inline void update(int pos) { 17 mx[pos] = pos; 18 if( v[mx[ch[pos][0]]] > v[mx[pos]] ) mx[pos] = mx[ch[pos][0]]; 19 if( v[mx[ch[pos][1]]] > v[mx[pos]] ) mx[pos] = mx[ch[pos][1]]; 20 } 21 inline void push(int pos) { 22 if( !rev[pos] ) return; 23 applyrev(ch[pos][0]) , 24 applyrev(ch[pos][1]) , 25 rev[pos] = 0; 26 } 27 inline int gid(int x) { 28 return x == ch[fa[x]][1]; 29 } 30 inline bool isroot(int x) { 31 return x != ch[fa[x]][0] && x != ch[fa[x]][1]; 32 } 33 inline void rotate(int x) { 34 push(fa[x]) , push(x); 35 const int f = fa[x] , id = gid(x); 36 fa[x] = fa[f]; 37 if( !isroot(f) ) ch[fa[f]][gid(f)] = x; 38 ch[f][id] = ch[x][id^1]; 39 if( ch[x][id^1] ) fa[ch[x][id^1]] = f; 40 ch[x][id^1] = f , fa[f] = x; 41 update(f) , update(x); 42 } 43 inline void pushchain(int x) { 44 if( fa[x] ) pushchain(fa[x]); 45 push(x); 46 } 47 inline void splay(int x) { 48 pushchain(x); 49 while( !isroot(x) ) { 50 if( !isroot(fa[x]) ) rotate(fa[x]); 51 rotate(x); 52 } 53 } 54 inline void access(int x) { 55 int y = 0; 56 while( x ) { 57 splay(x) , ch[x][1] = y , update(x) , 58 y = x , x = fa[x]; 59 } 60 } 61 inline void mkroot(int x) { 62 access(x) , splay(x) , applyrev(x); 63 } 64 inline void link(int x,int y) { 65 mkroot(x) , fa[x] = y; 66 } 67 inline void cut(int x,int y) { 68 mkroot(x); 69 access(y) , splay(y); 70 fa[x] = ch[y][0] = 0 , update(y); // now we assert x == ch[y][0] ( it must be true ) . 71 } 72 inline int query(int x,int y) { 73 mkroot(x); 74 access(y) , splay(y); 75 return mx[y]; // y shouldn't have ch[1] . 76 } 77 }t; 78 79 struct UnionFindSet { 80 int fa[maxn]; 81 inline int findfa(int x) { 82 return fa[x] == x ? x : fa[x] = findfa(fa[x]); 83 } 84 inline void merge(int x,int y) { 85 x = findfa(x) , y = findfa(y); 86 if( x != y ) fa[y] = x; 87 } 88 inline void init() { 89 for(int i=1;i<=n;i++) fa[i] = i; 90 } 91 }ufs; 92 93 struct Edge { 94 int x,y,w,id,sta; 95 friend bool operator < (const Edge &a,const Edge &b) { 96 return a.x != b.x ? a.x < b.x : a.y < b.y; 97 } 98 }es[maxm]; 99 bool cmp(const Edge &a,const Edge &b) { 100 return a.w < b.w; 101 } 102 103 int ope[maxn],x[maxn],y[maxn],id[maxn],ans[maxn]; // ope == 1 means modify . 104 105 inline void getans() { 106 for(int i=q;i;i--) { 107 if( !ope[i] ) { 108 int p = t.query(x[i],y[i]); 109 ans[i] = t.v[p]; 110 } else { 111 if( ufs.findfa(x[i]) != ufs.findfa(y[i]) ) { 112 ufs.merge(x[i],y[i]); 113 t.link(x[i],id[i]+n) , t.link(y[i],id[i]+n); 114 } else { 115 int p = t.query(x[i],y[i]); 116 if( t.v[p] > t.v[id[i]+n] ) { 117 t.cut(x[i],p) , t.cut(y[i],p); 118 t.link(x[i],id[i]+n) , t.link(y[i],id[i]+n); 119 } 120 } 121 } 122 } 123 } 124 inline void pre() { 125 std::sort(es+1,es+1+m,cmp) , ufs.init(); 126 for(int i=1;i<=m;i++) 127 if( !es[i].sta && ufs.findfa(es[i].x) != ufs.findfa(es[i].y) ) { 128 ufs.merge(es[i].x,es[i].y); 129 t.link(es[i].x,es[i].id+n) , t.link(es[i].y,es[i].id+n); 130 } 131 } 132 133 inline void init() { 134 for(int i=1;i<=m;i++) { 135 const int id = i + n; 136 t.v[id] = es[i].w , t.mx[id] = id; 137 } 138 std::sort(es+1,es+1+m); 139 for(int i=1;i<=q;i++) 140 if( ope[i] ) { 141 int at = std::lower_bound(es+1,es+1+m,(Edge){x[i],y[i],0,0,0}) - es; 142 es[at].sta = 1 , id[i] = es[at].id; 143 } 144 } 145 146 inline char nextchar() { 147 const int BS = 1 << 22; 148 static char buf[BS],*st=buf+BS,*ed=buf+BS; 149 if( st == ed ) ed = buf + fread(st=buf,1,BS,stdin); 150 return st == ed ? -1 : *st++; 151 } 152 inline int getint() { 153 int ret = 0 , ch; 154 while( !isdigit(ch=nextchar()) ); 155 do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) ); 156 return ret; 157 } 158 159 int main() { 160 n = getint() , m = getint() , q = getint(); 161 for(int i=1;i<=m;i++) { 162 es[i].x = getint() , es[i].y = getint() , es[i].w = getint() , es[i].id = i; 163 if( es[i].x > es[i].y ) std::swap( es[i].x , es[i].y ); 164 } 165 for(int i=1;i<=q;i++) { 166 ope[i] = getint() , x[i] = getint() , y[i] = getint() , --ope[i]; 167 if( x[i] > y[i] ) std::swap( x[i] , y[i] ); 168 } 169 init() , pre() , getans(); 170 for(int i=1;i<=q;i++) if( !ope[i] ) printf("%d\n",ans[i]); 171 return 0; 172 }
Bzoj5020:
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=5020
准确地说着不算是数据结构题,而是一道数学题。
他给的那三个函数显然都不可加,所以我们需要把他泰勒展开近似成多项式函数,然后LCT乱搞。
关于泰勒展开公式?
我们维护到x^17就行了,这种纠结的题多了T少了WA真是没办法……
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=1e5+1e2,maxl=20,lim=17; 6 7 double fac[maxl],c[maxl][maxl]; 8 9 struct LCT { 10 struct Node { 11 double dat[maxl]; 12 13 inline void in(const double &a,const double &b,const int &tpe) { 14 static double pa[maxl],pb[maxl]; 15 if( tpe != 3 ) { 16 *pa = *pb = 1; 17 for(int i=1;i<=lim;i++) pa[i] = pa[i-1] * a , pb[i] = pb[i-1] * b; 18 } 19 memset(dat,0,sizeof(dat)); 20 if( tpe == 1 ) { 21 for(int i=1,t=1;i<=lim;i+=2,t=-t) 22 for(int j=0;j<=i;j++) 23 dat[j] += pa[j] * pb[i-j] * c[i][j] * t / fac[i]; 24 } else if( tpe == 2 ) { 25 for(int i=0;i<=lim;i++) 26 for(int j=0;j<=i;j++) 27 dat[j] += pa[j] * pb[i-j] * c[i][j] / fac[i]; 28 } else if( tpe == 3 ) { 29 dat[1] = a , dat[0] = b; 30 } 31 } 32 inline double calc(const double &x) { 33 static double pows[maxl]; 34 *pows = 1; 35 for(int i=1;i<=lim;i++) pows[i] = pows[i-1] * x; 36 double ret = 0; 37 for(int i=0;i<=lim;i++) ret += dat[i] * pows[i]; 38 return ret; 39 } 40 41 friend Node operator + (const Node &a,const Node &b) { 42 Node ret; memset(ret.dat,0,sizeof(ret.dat)); 43 for(int i=0;i<=lim;i++) ret.dat[i] = a.dat[i] + b.dat[i]; 44 return ret; 45 } 46 }dat[maxn],sum[maxn]; 47 int ch[maxn][2],fa[maxn],rev[maxn]; 48 inline void apply(int pos) { 49 if( !pos ) return; 50 rev[pos] ^= 1 , 51 swap(ch[pos][0],ch[pos][1]); 52 } 53 inline void push(int pos) { 54 if( !rev[pos] ) return; 55 apply(ch[pos][0]) , apply(ch[pos][1]) , 56 rev[pos] = 0; 57 } 58 inline void update(int x) { 59 sum[x] = dat[x]; 60 if( ch[x][0] ) sum[x] = sum[x] + sum[ch[x][0]]; 61 if( ch[x][1] ) sum[x] = sum[x] + sum[ch[x][1]]; 62 } 63 inline bool isrt(int x) { 64 return x != ch[fa[x]][0] && x != ch[fa[x]][1]; 65 } 66 inline bool gid(int x) { 67 return x == ch[fa[x]][1]; 68 } 69 inline void rotate(int x) { 70 push(fa[x]) , push(x); 71 const int f = fa[x] , id = gid(x); 72 fa[x] = fa[f]; 73 if( !isrt(f) ) ch[fa[f]][gid(f)] = x; 74 ch[f][id] = ch[x][id^1]; 75 if( ch[x][id^1] ) fa[ch[x][id^1]] = f; 76 ch[x][id^1] = f , fa[f] = x; 77 update(f) , update(x); 78 } 79 inline void pushchain(int x) { 80 if( !isrt(x) ) pushchain(fa[x]); 81 push(x); 82 } 83 inline void upchain(int x) { 84 while(1) { 85 update(x); 86 if( isrt(x) ) break; 87 x = fa[x]; 88 } 89 } 90 inline void splay(int x) { 91 pushchain(x); 92 while( !isrt(x) ) { 93 if( !isrt(fa[x]) ) rotate(fa[x]); 94 rotate(x); 95 } 96 } 97 inline void access(int x) { 98 int y = 0; 99 while( x ) { 100 splay(x) , ch[x][1] = y , update(x); 101 y = x , x = fa[x]; 102 } 103 } 104 inline void mkrt(int x) { 105 access(x) , splay(x) , apply(x); 106 } 107 inline void link(int x,int y) { 108 mkrt(x) , fa[x] = y; 109 } 110 inline void cut(int x,int y) { 111 mkrt(x) , access(y) , splay(y); 112 ch[y][0] = fa[x] = 0 , update(y); 113 } 114 inline int findfa(int x) { 115 while( fa[x] ) x = fa[x]; 116 return x; 117 } 118 inline Node query(int x,int y) { 119 mkrt(x) , access(y) , splay(y); 120 return sum[y]; 121 } 122 }T; 123 inline void pre() { 124 *fac = 1; 125 for(int i=1;i<=lim;i++) fac[i] = fac[i-1] * i; 126 c[0][0] = 1; 127 for(int i=1;i<=lim;i++) { 128 c[i][0] = 1; 129 for(int j=1;j<=i;j++) c[i][j] = c[i-1][j-1] + c[i-1][j]; 130 } 131 } 132 133 int main() { 134 static int n,m; 135 static char o[10]; 136 static double a,b; 137 pre(); 138 scanf("%d%d%*s",&n,&m); 139 for(int i=1,t;i<=n;i++) { 140 scanf("%d%lf%lf",&t,&a,&b); 141 T.dat[i].in(a,b,t); 142 } 143 for(int i=1,t,x,y;i<=m;i++) { 144 scanf("%s",o); 145 if( *o == 'a' ) { 146 scanf("%d%d",&x,&y) , ++x , ++y; 147 T.link(x,y); 148 } else if( *o == 't' ) { 149 scanf("%d%d%lf",&x,&y,&a) , ++x , ++y; 150 if( T.findfa(x) != T.findfa(y) ) puts("unreachable"); 151 else { 152 LCT::Node ans = T.query(x,y); 153 printf("%.8e\n",ans.calc(a)); 154 } 155 } else if( *o == 'm' ) { 156 scanf("%d%d%lf%lf",&x,&t,&a,&b) , ++x; 157 T.splay(x); 158 T.dat[x].in(a,b,t); 159 } else if( *o == 'd' ) { 160 scanf("%d%d",&x,&y) , ++x , ++y; 161 T.cut(x,y); 162 } 163 } 164 return 0; 165 }
最后说几句废话(好像这篇全都是废话?):
为什么我这种辣鸡颓佬还能当Bzoj年榜Rank1?