平时四测
Posted edsheeran
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了平时四测相关的知识,希望对你有一定的参考价值。
题解:
可持久化并查集(今天早上现学习YY的, 启发式合并logN, 就不用路径压缩了, 不然会要N*logN*logN的空间)
#include<bits/stdc++.h> using namespace std; const int M = 100005; int n, m; struct Node { int fa, siz; Node *ls, *rs; }pool[M * 32], *tail = pool, *root[M]; Node * build(int lf = 1, int rg = n){ Node *nd = ++tail; if(lf == rg)nd->fa = lf, nd->siz = 1; else{ int mid = (lf + rg) >> 1; nd->ls = build(lf, mid); nd->rs = build(mid + 1, rg); } return nd; } #define Ls nd->ls, lf, mid #define Rs nd->rs, mid + 1, rg Node * add(int x, int fa, Node *nd, int lf = 1, int rg = n){ Node *nnd = ++tail; if(lf == rg){ nnd->fa = fa; nnd->siz = nd->siz; } else { int mid = (lf + rg) >> 1; if(x <= mid){ nnd->rs = nd->rs; nnd->ls = add(x, fa, Ls); } else { nnd->ls = nd->ls; nnd->rs = add(x, fa, Rs); } } return nnd; } Node * query(int x, Node *nd, int lf = 1, int rg = n){ if(lf == rg)return nd; else{ int mid = (lf + rg) >> 1; if(x <= mid) return query(x, Ls); else return query(x, Rs); } } Node * kd(int x, int tt, Node *nd, int lf = 1, int rg = n){ Node *nnd = ++tail; if(lf == rg)nnd->siz = tt, nnd->fa = nd->fa; else{ int mid = (lf + rg) >> 1; if(x <= mid) { nnd->rs = nd->rs; nnd->ls = kd(x, tt, Ls); } else { nnd->ls = nd->ls; nnd->rs = kd(x, tt, Rs); } } return nnd; } Node * find(int x, Node *nd){ Node *f = query(x, nd); if(f->fa == x) return f; return find(f->fa, nd); } int main(){ freopen("build.in","r",stdin); freopen("build.out","w",stdout); scanf("%d%d", &n, &m); root[0] = build(); int opt, x, y; int lst = 0; for(int i = 1; i <= m; i++){ scanf("%d%d%d", &opt, &x, &y); x += lst, y += lst; if(opt == 1){ Node *fx = find(x, root[i - 1]); Node *fy = find(y, root[i - 1]); if(fx->fa == fy->fa){ root[i] = root[i - 1]; continue; } int tt = fx->siz + fy->siz; if(fx->siz > fy->siz){ root[i] = add(fy->fa, fx->fa, root[i - 1]); root[i] = kd(fx->fa, tt, root[i]); } else { root[i] = add(fx->fa, fy->fa, root[i - 1]); root[i] = kd(fy->fa, tt, root[i]); //printf("%d %d ", find(1, root[i])->fa, find(2, root[i])->siz); } } else { root[i] = root[i - 1]; Node *ans = find(y, root[x]); //printf("%d ", ans->fa); lst = ans->siz; printf("%d ", lst); } //printf("%d ", i); } }
题解的std:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int MAXN=100005 ; int n, m, fa[MAXN], times[MAXN], h[MAXN], nowT, size[MAXN]; struct Info{ int tm, size ; Info(int _tm=0,int _size=0){ tm=_tm , size=_size; } }; vector<Info> vec[MAXN] ; vector<Info>::iterator it ; bool cmp(const Info &a, const Info &b){ return a.tm < b.tm ; } int findFa(int a){ if(fa[a]==a) return a; return findFa(fa[a]) ; } void mergeNodes(int u,int v){ int fu=findFa(u), fv=findFa(v) ; if(fu==fv) return ; if(h[fu]<h[fv]) swap(fu,fv) ; fa[fv]=fu, size[fu]+=size[fv], times[fv]=nowT ; if(h[fu]==h[fv]) h[fu]++ ; vec[fu].push_back(Info(nowT,size[fu])) ; } int query(int t, int a){ while(a!=fa[a] && times[a]<=t) a=fa[a] ; it=upper_bound(vec[a].begin(),vec[a].end(),Info(t,0),cmp) ; --it ; return it->size ; } int main(){ freopen("build.in","r",stdin) ; freopen("build.out","w",stdout) ; scanf("%d%d",&n,&m) ; for(int i=1;i<=n;++i) fa[i]=i, vec[i].push_back(Info(0,1)), h[i]=1, size[i]=1 ; int lastans=0 ; for(int i=1;i<=m;++i){ int t, u, v ; nowT=i ; scanf("%d%d%d",&t,&u,&v) ; u+=lastans , v+=lastans ; if(t==1){ mergeNodes(u,v) ; } else if(t==2){ printf("%d ",lastans=query(u,v)) ; } } return 0 ; }
第二题:
我开始想的是f[ i ]表示A的最大权值, A用MAX去更新后面, B选的时候用MIN更新后面,这是误区1, DP一般是一种最优值;
误区2,我是正着更新的,但实际上选下个已经和前面没有关系了, 而是一个新局面, 并且有后效性啊;
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #ifdef WIN32 #define myLL "%I64d" #else #define myLL "%lld" #endif using namespace std; const int MAXN=1000005 ; int n, A[MAXN]; long long sum[MAXN], dp[MAXN] ; int main(){ freopen("distribute.in","r",stdin) ; freopen("distribute.out","w",stdout) ; scanf("%d",&n) ; for(int i=1;i<=n;++i) scanf("%d",&A[i]) ; for(int i=n;i>=1;--i) sum[i]=sum[i+1]+A[i] ; dp[n]=A[n] ; for(int i=n-1;i>=1;--i) dp[i]=max(dp[i+1], sum[i+1] - dp[i+1] + A[i]) ; printf(myLL" ", dp[1]) ; return 0 ; }
第三题:
点双压边
#include<bits/stdc++.h> using namespace std; const int M = 100005; int knum, tot, low[M], dfn[M], tag[M], tp, t[M << 1], h[M], idc, q[M << 1]; bool vis[M << 1], isans[M << 1]; struct edge{int v, nxt;}G[M << 1]; void add(int u, int v){ G[++tot].v = v, G[tot].nxt = h[u], h[u] = tot; } void tarjan(int u, int lst){ dfn[u] = low[u] = ++idc; for(int i = h[u]; i; i = G[i].nxt){ if((i^1) == lst) continue; int v = G[i].v; if(!vis[i]) vis[i] = vis[i^1] = 1, t[++tp] = i; if(!dfn[v]){ tarjan(v, i); low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]){ ++knum; int qnum = 0, cnt = 0, s; do{ s = t[tp--]; if(tag[G[s].v] != knum) tag[G[s].v] = knum, cnt++; if(tag[G[s^1].v] != knum) tag[G[s^1].v] = knum, cnt++; q[++qnum] = s; }while(s != i); if(cnt == qnum){ for(int i = 1; i <= qnum; i++) isans[q[i]] = isans[q[i]^1] = 1; } } } else low[u] = min(low[u], dfn[v]); } } int main(){ freopen("find.in","r",stdin); freopen("find.out","w",stdout); int n, m; tot++; scanf("%d%d", &n, &m); int u, v; for(int i = 1; i <= m; i++){ scanf("%d%d", &u,&v); add(u, v); add(v, u); } for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i, 0); int cnt = 0; for(int i = 2; i <= 2*m; i+=2) if(isans[i]) q[++cnt] = i/2; if(!cnt) return !puts("0"); printf("%d ", cnt); for(int i = 1; i <= cnt; i++) printf("%d ", q[i]); }
以上是关于平时四测的主要内容,如果未能解决你的问题,请参考以下文章