9月做题记录
Part 1.图论
1.分层图最短路
P6100 [USACO19FEB] Painting the Barn G
#include<bits/stdc++.h> using namespace std; const int N=1e5+5,M=205,K=1e5+5; int n,m=200,k,h[M][M],res,ans,cntx[M][M],cnty[M][M],ansx[M][M],ansy[M][M],nx[2][M],ny[2][M],tmp; int main() { cin>>n>>k; for(int i=1;i<=n;++i) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); ++x1,++y1,++x2,++y2; h[x1][y1]++,h[x2][y2]++; h[x1][y2]--,h[x2][y1]--; } for(int i=1;i<=m;++i) { for(int j=1;j<=m;++j) h[i][j]+=h[i-1][j]+h[i][j-1]-h[i-1][j-1],res+=(h[i][j]==k); } for(int i=1;i<=m;++i) { for(int j=1;j<=m;++j) { cntx[i][j]=cntx[i-1][j]+(h[i][j]==k-1)-(h[i][j]==k); cnty[i][j]=cnty[i][j-1]+(h[i][j]==k-1)-(h[i][j]==k); } } for(int i=1;i<=m;++i) { for(int j=1;j<=i;++j) { tmp=0; for(int c=1;c<=m;++c) { tmp=max(tmp+cntx[i][c]-cntx[j-1][c],0); ansx[i][j]=max(ansx[i][j],tmp); } } } for(int i=1;i<=m;++i) { for(int j=1;j<=i;++j) { tmp=0; for(int c=1;c<=m;++c) { tmp=max(tmp+cnty[c][i]-cnty[c][j-1],0); ansy[i][j]=max(ansy[i][j],tmp); } } } for(int i=1;i<=m;++i) { nx[0][i]=nx[0][i-1]; for(int j=1;j<=i;++j) nx[0][i]=max(nx[0][i],ansx[i][j]); } for(int i=m;i>=1;--i) { nx[1][i]=nx[1][i+1]; for(int j=m;j>=i;--j) nx[1][i]=max(nx[1][i],ansx[j][i]); } for(int i=1;i<=m;++i) { ny[0][i]=ny[0][i-1]; for(int j=1;j<=i;++j) ny[0][i]=max(ny[0][i],ansy[i][j]); } for(int i=m;i>=1;--i) { ny[1][i]=ny[1][i+1]; for(int j=m;j>=i;--j) ny[1][i]=max(ny[1][i],ansy[j][i]); } ans=res; for(int i=2;i<=m;++i) ans=max(ans,res+nx[0][i-1]+nx[1][i]); for(int i=2;i<=m;++i) ans=max(ans,res+ny[0][i-1]+ny[1][i]); printf("%d\n",ans); return 0; }
P3119 [USACO15JAN] Grass Cownoisseur G
主要是需要缩点,分层图最短路就比较板了。
#include<bits/stdc++.h> using namespace std; const int N=500005; //要先缩点! int n,m,h[N],e[N],ne[N],idx =1,deg[N],f[N]; int dfn[N],low[N],tmp,q[N],indx,scc[N],tot,num[N],top; void add(int a,int b){ e[idx] = b; ne[idx] = h[a]; h[a]=idx++; } void tarjan(int u) { dfn[u]=low[u]=++tmp; q[++top] = u; for(int i=h[u],v;i;i=ne[i]){ int j=e[i]; if(!dfn[j]){ tarjan(j); low[u]=min(low[u],low[j]); }else if(!scc[j]){ low[u] = min(low[u],dfn[j]); } } if(dfn[u]==low[u]){ ++tot; do{ ++num[scc[q[top]] = tot]; }while(q[top--]!=u); } } vector<int>g[N]; int main(){ cin>>n>>m; for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; add(x,y); add(y,x+n); add(x+n,y+n); } tarjan(1); for(int i=1;i<=n*2;i++){ if(dfn[i]){ for(int k=h[i];k;k=ne[k]){ int j=e[k]; if(scc[i]!=scc[j]){ g[scc[i]].push_back(scc[j]),++deg[scc[j]]; } } } } int l=0,r=0; for(int i=1;i<=tot;i++){ if(!deg[i]) q[r++] = i; f[i]=-0x3f3f3f3f; } while(l < r){ int u= q[l++]; if(u==scc[1]) f[u]=0; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!--deg[v]) q[r++] = v; f[v] = max(f[v],f[u]+num[v]); } } cout<<f[scc[n+1]]; return 0; }
part 2:数据结构
主要还是在练线段树qwq
P4145 上帝造题的七分钟 2 / 花神游历各国
线段树的区间开方操作。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int INF=1e9+7,MAXN=1e5+10,MAXNODE=MAXN*4; int N,M; LL tmp[MAXN],sum[MAXNODE],maxv[MAXNODE]; inline void push_up(int x){ sum[x]=sum[x<<1]+sum[x<<1|1]; maxv[x]=max(maxv[x<<1],maxv[x<<1|1]); } void init(int x,int l,int r){ if(l==r){ sum[x]=maxv[x]=tmp[l]; return; } int mid=(l+r)>>1; init(x<<1,l,mid); init(x<<1|1,mid+1,r); push_up(x); } LL query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return sum[x]; int mid=(l+r)>>1; LL ret=0; if(ql<=mid) ret+=query(x<<1,l,mid,ql,qr); if(mid<qr) ret+=query(x<<1|1,mid+1,r,ql,qr); return ret; } void update(int x,int l,int r,int ql,int qr){ if(l==r){ maxv[x]=sqrt(maxv[x]); sum[x]=sqrt(sum[x]); return; } if(maxv[x]<=1) return; int mid=(l+r)>>1; if(ql<=mid&&maxv[x<<1]>1) update(x<<1,l,mid,ql,qr); if(mid<qr&&maxv[x<<1|1]>1) update(x<<1|1,mid+1,r,ql,qr); push_up(x); } int main(){ scanf("%d",&N); for(int i=1;i<=N;i++) scanf("%lld",tmp+i); init(1,1,N); scanf("%d",&M); for(int i=1,k,l,r;i<=M;i++){ scanf("%d%d%d",&k,&l,&r); if(l>r) swap(l,r); if(k) printf("%lld\n",query(1,1,N,l,r)); else update(1,1,N,l,r); } return 0; }
P4551 最长异或路径
一道01 trie好题!
#include<bits/stdc++.h> using namespace std; //过了样例,如何评价? const int MAXN=100010; int s[MAXN],trie[MAXN*31][2]; int n,tot; struct edge{ int to,w; }; vector<edge> p[MAXN]; void dfs(int x,int fa){ for(int i=0;i<p[x].size();i++){ int nxt=p[x][i].to; if(nxt!=fa){ s[nxt]=s[x]^p[x][i].w; dfs(nxt,x); } } } void insert(int val){ int x=0; for(int i=(1<<30);i;i>>=1){ int a=bool(val&i); if(!trie[x][a]) trie[x][a]=++tot; x=trie[x][a]; } } int find(int val){ int ans=0; int x=0; for(int i=(1<<30);i;i>>=1){ int a=bool(val&i); if(trie[x][!a]){ //这里调了半天!/kk ans+=i; x=trie[x][!a]; }else{ x=trie[x][a]; } } //哪个大冤种忘记return了? return ans; } int main(){ cin>>n; int a,b,c; for(int i=1;i<n;++i){ cin>>a>>b>>c; p[a].push_back((edge){b,c}); p[b].push_back((edge){a,c}); } dfs(1,-1); for(int i=1;i<=n;++i){ insert(s[i]); } int ans=0; for(int i=1;i<=n;++i){ ans=max(ans,find(s[i])); //cout<<find(s[i])<<' '; } cout<<ans; return 0; }
P6136 【模板】普通平衡树(数据加强版)
这里提供3种写法,研究了好久。
本来还想用01trie写的,但是不会后缀树,只能跑到84pts,不放丑陋的代码!
1.FHQ treap
#include<bits/stdc++.h> using namespace std; //FHQ treap试试? #define int long long const int N=4e6+5; struct Node{ int l, r; int key; int sz, v; #define ls tr[u].l #define rs tr[u].r }tr[N]; int root, idx; void pushup(int u){ tr[u].sz=tr[ls].sz+tr[rs].sz+1; } int add(int v){ ++idx; tr[idx].key=rand(), tr[idx].sz=1, tr[idx].v=v; return idx; } int merge(int x, int y){ if(!x || !y) return x+y; if(tr[x].key>tr[y].key){ tr[x].r=merge(tr[x].r, y); pushup(x); return x; } else{ tr[y].l=merge(x, tr[y].l); pushup(y); return y; } } void split(int u, int val, int &x, int &y){ if(!u) return x=y=0, void(); if(tr[u].v<=val) x=u, split(rs, val, rs, y); else y=u, split(ls, val, x, ls); pushup(u); } void insert(int v){ int x, y; split(root, v, x, y); root=merge(x, merge(add(v), y)); } void remove(int v){ int x, y, z; split(root, v, x, z); split(x, v-1, x, y); y=merge(tr[y].l, tr[y].r); root=merge(merge(x, y), z); } int val4rk(int v){ int x, y; split(root, v-1, x, y); int res=tr[x].sz+1; root=merge(x, y); return res; } int rk4val(int k){ int u=root; while(u){ if(tr[ls].sz+1==k) return tr[u].v; else if(tr[ls].sz>=k) u=ls; else k-=tr[ls].sz+1, u=rs; } return -1; } int get_prev(int v){ int x, y; split(root, v-1, x, y); int u=x; while(rs) u=rs; int res=tr[u].v; root=merge(x, y); return res; } int get_next(int v){ int x, y; split(root, v, x, y); int u=y; while(ls) u=ls; int res=tr[u].v; root=merge(x, y); return res; } int n,m,tmp,x,op,last; signed main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>x; insert(x); } for(int i=1;i<=m;i++) { //int tmp=last; cin>>op; cin>>x; x^=last; if(op==1) insert(x); else if(op==2) remove(x); else if(op==3) last = val4rk(x); else if(op==4) last = rk4val(x); else if(op==5) last = get_prev(x); else if(op==6) last = get_next(x); //if(i!=1){ // tmp=last; //} //else if(op>=3) { tmp^=last; //printf("%d %d\n",last,tmp); } } cout<<tmp; return 0; }
2.splay
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1000010; int read() { int ans = 0; char c = getchar(), last = ' '; while(c < '0' || c > '9') last = c, c = getchar(); while(c >= '0' && c <= '9') ans = (ans << 1) + (ans << 3) + c - '0', c = getchar(); if(last == '-') ans = - ans; return ans; } int ecnt; struct tree { int l, r, siz, rad, val; }t[N<<2]; unsigned long long seed = 1; int Rand() { seed *= 260817; return int(seed); } void update(int cnt) { t[cnt].siz = t[t[cnt].l].siz + t[t[cnt].r].siz + 1; } int New(int x) { t[++ecnt].val = x; t[ecnt].rad = Rand(); t[ecnt].siz = 1; return ecnt; } void split(int cnt, int k, int &x, int &y) { if(!cnt) { x = y = 0; return; } if(t[cnt].val <= k) { x = cnt; split(t[cnt].r, k, t[cnt].r, y); } if(t[cnt].val > k) { y = cnt; split(t[cnt].l, k, x, t[cnt].l); } update(cnt); } int merge(int x, int y) { if(x == 0) return y; if(y == 0) return x; if(t[x].rad <= t[y].rad) { t[x].r = merge(t[x].r, y); update(x); return x; } else if(t[x].rad > t[y].rad) { t[y].l = merge(x, t[y].l); update(y); return y; } } int kth(int cnt, int k) { if(t[t[cnt].l].siz + 1 == k) return t[cnt].val; if(t[t[cnt].l].siz >= k) return kth(t[cnt].l, k); else return kth(t[cnt].r, k - t[t[cnt].l].siz - 1); } int n, m, rt; int last = 0, ans = 0; int main() { scanf("%d%d", &n, &m); int x, y, z, k, opt; for(int i = 1; i <= n; i ++) { k = read(); split(rt, k, x, y); rt = merge(merge(x, New(k)), y); } for(int i = 1; i <= m; i ++) { opt = read(), k = read(); k ^= last; if(opt == 1) { split(rt, k, x, y); rt = merge(merge(x, New(k)), y); } if(opt == 2) { split(rt, k, x, y); split(x, k - 1, x, z); z = merge(t[z].l, t[z].r); rt = merge(merge(x, z), y); } if(opt == 3) { split(rt, k - 1, x, y); last = t[x].siz + 1; ans ^= last; // printf("%lld\n", last); rt = merge(x, y); } if(opt == 4) { last = kth(rt, k); ans ^= last; // printf("%lld\n", last); } if(opt == 5) { split(rt, k - 1, x, y); last = kth(x, t[x].siz); ans ^= last; // printf("%lld\n", last); rt = merge(x, y); } if(opt == 6) { split(rt, k, x, y); last = kth(y, 1); ans ^= last; // printf("%lld\n", last); rt = merge(x, y); } } printf("%d", ans); }
3.WBLT(最快)
#include<bits/stdc++.h> using namespace std; const int N=1e7; const double A=1.0/3.0; struct node{int l,r,size,c;}tr[2*N]; int len,root,sta[N],tp; inline int ins(int l,int r) { int now=tp?sta[tp--]:++len; tr[now].l=l;tr[now].r=r;tr[now].c=tr[r].c; tr[now].size=tr[l].size+tr[r].size;return now; } inline void vclean(int x){sta[++tp]=x;tr[x].l=tr[x].r=tr[x].c=tr[x].size=0;} inline void vcopy(int y,int x){tr[x].l=tr[y].l;tr[x].r=tr[y].r;tr[x].size=tr[y].size;tr[x].c=tr[y].c;} inline int vnew(int c){int now=tp?sta[tp--]:++len;tr[now].size=1;tr[now].c=c;return now;} inline void pushup(int x) { int l=tr[x].l,r=tr[x].r;if(!tr[l].size)return; tr[x].c=tr[r].c;tr[x].size=tr[l].size+tr[r].size; } inline void rotate(int x,bool p) { if(p) { int l=tr[x].l; tr[x].r=ins(tr[l].r,tr[x].r); tr[x].l=tr[l].l;vclean(l); } else { int r=tr[x].r; tr[x].l=ins(tr[x].l,tr[r].l); tr[x].r=tr[r].r;vclean(r); } } inline bool pd(int x){return((double)(min(tr[tr[x].l].size,tr[tr[x].r].size))>=A*(double)(tr[x].size));} inline void maintain(int x) { if(pd(x))return; rotate(x,tr[tr[x].l].size>tr[tr[x].r].size); } void add(int now,int x) { if(tr[now].size==1) { tr[now].l=vnew(min(tr[now].c,x)); tr[now].r=vnew(max(tr[now].c,x)); pushup(now);return; } maintain(now); int l=tr[now].l,r=tr[now].r; if(x<=tr[l].c)add(l,x);else add(r,x);pushup(now); } void del(int now,int fa,int x) { if(tr[now].size==1) { int newone=(tr[fa].l==now)?tr[fa].r:tr[fa].l; vcopy(newone,fa);vclean(now);vclean(newone);return; } maintain(now); int l=tr[now].l,r=tr[now].r; if(x<=tr[l].c)del(l,now,x);else del(r,now,x);pushup(now); } int findrank(int now,int x) { if(tr[now].size==1)return 1;maintain(now); int l=tr[now].l,r=tr[now].r; if(x<=tr[l].c)return findrank(l,x); else return tr[l].size+findrank(r,x); } int findshuz(int now,int k) { if(tr[now].size==k)return tr[now].c; maintain(now);int l=tr[now].l,r=tr[now].r; if(k<=tr[l].size)return findshuz(l,k); else return findshuz(r,k-tr[l].size); } int ans,last,opt,x; int main() { int n,m; scanf("%d%d",&n,&m); root=vnew(1<<30); for(int i=1;i<=n;i++){ cin>>x; add(root,x); } for(int i=1;i<=m;i++) { scanf("%d%d",&opt,&x); x^=last; if(opt==1)add(root,x); else if(opt==2)del(root,0,x); else if(opt==3)last=findrank(root,x); else if(opt==4)last=findshuz(root,x); else if(opt==5)last=findshuz(root,findrank(root,x)-1); else last=findshuz(root,findrank(root,x+1)); if(opt>=3) ans^=last; } cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话