test41
输出字符串
按照题意模拟即可。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_backusing namespace std;const int N=100005, M=26;int n, T, cnt[N];
string s[N];
vector<int> str[M];bool operator<(const string i,const string j) {int l=min(i.size(),j.size());up(u,0,l-1) if(i[u]!=j[u]) return i[u]<j[u];return i.size()<j.size();
}signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> T;up(i,1,n) {cin >> s[i];str[s[i][0]-'a'].pb(i);}up(i,0,25) sort(str[i].begin(),str[i].end(),[](int i,int j){return s[i]<s[j];});while(T--) {char u;cin >> u;int v=u-'a';if(!str[v].size()) cout << '\n';else {cout << s[str[v][cnt[v]]] << '\n';cnt[v]=(cnt[v]+1)%(int)str[v].size();}}return 0;
}
最优排列翻转
考虑一个 \(p_i\) 只有在 \(\frac{i+p_i}{2}\) 为中点(或者中缝)时操作才会有正贡献,被操作区间包含且不为中点且原先贡献的操作才会有负贡献。后者是简单关系,不妨把前者挂在中点上,然后枚举中间考虑怎么做,发现可以只取挂上去的长度,那排序之后枚举就好了。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_backusing namespace std;const int N=500005;int n, p[N], sum[N], cnt, ans;
vector<int> L[N], R[N];signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n;up(i,1,n) cin >> p[i];up(i,1,n) {sum[i]=sum[i-1]+(p[i]==i);if(p[i]!=i) {int l=(i+p[i])/2, r=(abs(i-p[i])+1)/2;if((i+p[i])%2==0) L[l].pb(r); else R[l].pb(r); }}up(i,1,n) {cnt=0, sort(L[i].begin(),L[i].end());for(int u:L[i]) ans=max(ans,(++cnt)-(sum[i+u-1]-sum[i-u])+(p[i]==i));cnt=0, sort(R[i].begin(),R[i].end());for(int u:R[i]) ans=max(ans,(++cnt)-(sum[i+u]-sum[i-u]));}cout << ans << '\n';return 0;
}
比赛
不会做了半天发现自己不知道花果山为 \(1\) /fad
考虑把 \(1\) 提成根,设 \(f_i\) 为从 \(i\) 开始走的答案,转移就往 \(k\) 内的祖先转移,这个可以 dfs 的时候取栈的后缀,线段树优化 dp 即可。
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)using namespace std;const int N=200005;int n, m, T, dep[N], f[N], tr[N<<2];
vector<int> to[N];
vector<pii> lap[N]; void modify(int x,int v,int p=1,int s=1,int e=n) {if(s==e) return tr[p]=v, void();int mid=(s+e)>>1;if(x<=mid) modify(x,v,ls(p),s,mid);if(x>mid) modify(x,v,rs(p),mid+1,e);tr[p]=min(tr[ls(p)],tr[rs(p)]);
}int query(int l,int r,int p=1,int s=1,int e=n) {if(l<=s&&e<=r) return tr[p];int mid=(s+e)>>1, res=1e18;if(l<=mid) res=query(l,r,ls(p),s,mid);if(r>mid) res=min(res,query(l,r,rs(p),mid+1,e));return res;
}void dfs(int x,int fad) {dep[x]=dep[fad]+1;if(dep[x]>1) for(pii u:lap[x]) f[x]=min(f[x],query(dep[x]-u.first,dep[x]-1)+u.second);modify(dep[x],f[x]);for(int y:to[x]) if(y!=fad) dfs(y,x);
}signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m >> T;up(i,2,n) {int u, v;cin >> u >> v;to[u].pb(v);to[v].pb(u); }while(m--) {int x, k, v;cin >> x >> k >> v;lap[x].pb(mp(k,v));}memset(f,0x3f,sizeof(f));memset(tr,0x3f,sizeof(tr));f[1]=0, dfs(1,0);while(T--) {int x;cin >> x;cout << f[x] << '\n';}return 0;
}
圣杯战争
首先肯定是一条边来贡献,假设不要某条边而要起点终点相同的另一条链,那么不如要链上肯定存在的连接不同颜色的边,所以题目变成了动态修改颜色+查询两端颜色不同的边的最小权。
发现可以取 mst 出来,然后瓶颈在于暴力复杂度是 \(O(\sum in_u)\) 的,然后这个时候没睡好被根号分治占领大脑了,所以感觉 mst 带不来对根号分治的优化扔掉了。然后你可以直接上一个根号分治,大对大、小对小的贡献是容易的,然后考虑怎么处理小对大的贡献,可以在大点上维护某种颜色的答案是多少,然后再快速查找最大答案、这个排序之后只用遍历俩颜色。具体而言,维护两个 multiset,一个储存所有儿子的信息,快速查询某种颜色的最小权,一个储存所有颜色的信息,对每种颜色的权值排序,都要支持动态加删。
然后稍微有一点点被卡常,本地 o3 <2s 但是 lgj 机子稍微慢一点,捡回来扔掉的 mst,可以给边的规模 \(\times \frac{1}{2}\) 然后就可以过惹。所以话又说回来了,你把 mst 提出来,上面的做法从小对大改成儿子对父亲,就是单 \(\log\) 做法了,感觉写起来估计差不多吧(
#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fir first
#define sec secondusing namespace std;const int N=200005;int n, m, K, T, B, gp[N], in[N], dsu[N];
vector<int> diff;
vector<pii> to[N];
multiset<int> com;
multiset<pii> L[N], R[N];
map<pii,int> dis;
struct node { int x, y, w; } p[N<<1];int get(int x) { return x==dsu[x]?x:dsu[x]=get(dsu[x]); }signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> m >> K >> T, B=sqrt(2*m);up(i,1,m) cin >> p[i].x >> p[i].y >> p[i].w; sort(p+1,p+1+m,[](node i,node j){return i.w<j.w;});up(i,1,n) dsu[i]=i;up(i,1,m) {int u=p[i].x, v=p[i].y, w=p[i].w;int x=get(u), y=get(v);if(x==y) continue;++in[u], ++in[v], dsu[x]=y;dis[mp(u,v)]=dis[mp(v,u)]=w;to[u].pb(mp(v,w));to[v].pb(mp(u,w));}up(i,1,n) cin >> gp[i];up(i,1,n) in[i]=(in[i]>B);up(i,1,n) {for(pii u:to[i]) {int j=u.fir, w=u.sec;if(i<j&&in[i]==in[j]&&gp[i]!=gp[j]) com.insert(w);}if(in[i]) {diff.pb(i);for(pii u:to[i]) {int j=u.fir, w=u.sec;if(in[j]) continue;auto it=L[i].lower_bound(mp(gp[j],0));if(it==L[i].end()||it->fir!=gp[j]) R[i].insert(mp(w,gp[j]));else if(w<it->sec) R[i].erase(R[i].find(mp(it->sec,it->fir))), R[i].insert(mp(w,gp[j]));L[i].insert(mp(gp[j],w));}for(pii u:R[i]) if(u.sec!=gp[i]) { com.insert(u.fir); break; }}}while(T--) {int i, pre, suf;cin >> i >> suf;pre=gp[i], gp[i]=suf;if(in[i]) {for(int j:diff) {if(dis.find(mp(i,j))==dis.end()) continue;int w=dis[mp(i,j)];gp[i]=pre;if(gp[i]==gp[j]) com.erase(com.find(w));gp[i]=suf;if(gp[i]==gp[j]) com.insert(w);}gp[i]=pre;for(pii u:R[i]) if(u.sec!=gp[i]) { com.erase(com.find(u.fir)); break; }gp[i]=suf;for(pii u:R[i]) if(u.sec!=gp[i]) { com.insert(u.fir); break; }}else {for(pii u:to[i]) {int j=u.fir, w=u.sec;if(in[j]) {gp[i]=pre;for(pii u:R[j]) if(u.sec!=gp[j]) { com.erase(com.find(u.fir)); break; }L[j].erase(L[j].find(mp(gp[i],w)));if(R[j].find(mp(w,gp[i]))!=R[j].end()) {R[j].erase(R[j].find(mp(w,gp[i])));auto it=L[j].lower_bound(mp(gp[i],0));if(it!=L[j].end()&&it->fir==gp[i]) R[j].insert(mp(it->sec,it->fir));}gp[i]=suf;auto it=L[j].lower_bound(mp(gp[i],0));if(it==L[j].end()||it->fir!=gp[i]) R[j].insert(mp(w,gp[i]));else if(w<it->sec) R[j].erase(R[j].find(mp(it->sec,it->fir))), R[j].insert(mp(w,gp[i]));L[j].insert(mp(gp[i],w));for(pii u:R[j]) if(u.sec!=gp[j]) { com.insert(u.fir); break; }}else {gp[i]=pre;if(gp[i]!=gp[j]) com.erase(com.find(w));gp[i]=suf;if(gp[i]!=gp[j]) com.insert(w);}}}cout << *com.begin() << '\n';}return 0;
}