A. 倚天剑的愤怒
分析
(15) 分的做法是从前往后扫,遇到不合法的时候就从前面找一个最小的减掉
正解需要倒着考虑
维护一个 (multiset)
如果遇到一个负数直接扔到 (multiset) 里
如果遇到一个正数,那么我们肯定想让它抵消掉尽可能多的负数,直到它变成零
最后把剩下的负数做一个前缀和,二分查找即可
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<set>
#define rg register
const int maxn=1e6+5;
int n,m,a[maxn],cnt,tp;
long long beg,sum[maxn];
std::multiset<int> s;
#define sit std::multiset<int>::iterator
int main(){
scanf("%d%d",&n,&m);
for(rg int i=1;i<=n;i++) scanf("%d",&a[i]);
for(rg int i=n;i>=1;i--){
if(a[i]<0) s.insert(-a[i]);
else {
while(!s.empty()){
rg int tmp=*s.begin();
s.erase(s.begin());
if(a[i]>=tmp) a[i]-=tmp;
else {
s.insert(tmp-a[i]);
break;
}
}
}
}
for(rg sit it=s.begin();it!=s.end();++it) sum[++tp]=*it;
for(rg int i=1;i<=tp;i++) sum[i]+=sum[i-1];
for(rg int i=1;i<=m;i++){
scanf("%lld",&beg);
if(beg>=sum[tp]) cnt=0;
else cnt=tp-(std::upper_bound(sum+1,sum+1+tp,beg)-sum)+1;
printf("%d
",cnt);
}
return 0;
}
B. 原谅
分析
考试的时候挂成了 (40) 分
调了一下午+一晚上,拍了几千组没拍出错
然后去 (51Nod) 上下载数据,手调 (10000) 个节点的树
发现是删叶子节点的时候删挂了
一条边我强制让权值小的连向权值大的,然后没考虑权值相等的
这样在更新的时候就有可能更新不到
这道题的思路还是比较简单的
将点按照权值从大到小排序
对于当前一个值 (x)
先把权值大于等于 (x) 的加入并查集
然后删权值等于 (x) 的叶子节点,能删多少删多少
要求删完之后必须在一个联通块中并且联通块的大小小于等于 (k)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<vector>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
int n,m;
struct asd{
int zb,yb;
asd(){}
asd(rg int aa,rg int bb){
zb=aa,yb=bb;
}
}b[maxn];
int du[maxn],a[maxn],id[maxn],ans,fa[maxn],cnt,vis[maxn],tim,siz[maxn],maxsiz=1;
std::vector<int> g[maxn],g2[maxn];
bool cmp(rg int aa,rg int bb){
return a[aa]>a[bb];
}
int sta[maxn],tp;
int zhao(rg int xx){
if(xx==fa[xx]) return xx;
return fa[xx]=zhao(fa[xx]);
}
void bing(rg int xx,rg int yy){
xx=zhao(xx),yy=zhao(yy);
if(xx==yy) return;
fa[xx]=yy,siz[yy]+=siz[xx],siz[xx]=0;
maxsiz=std::max(maxsiz,siz[yy]);
cnt--;
}
std::queue<int> q;
void updat(rg int now){
for(rg int j=0;j<g[now].size();j++){
rg int u=g[now][j];
du[u]++,du[now]++;
}
sta[++tp]=now;
}
int main(){
n=read(),m=read();
for(rg int i=1;i<=n;i++) a[i]=read(),fa[i]=i,siz[i]=1;
rg int aa,bb;
for(rg int i=1;i<n;i++){
aa=read()+1,bb=read()+1;
if(a[aa]>a[bb]) g[bb].push_back(aa);
else g[aa].push_back(bb);
if(a[aa]==a[bb]) g2[aa].push_back(bb),g2[bb].push_back(aa);
}
for(rg int i=1;i<=n;i++) id[i]=i;
std::sort(id+1,id+1+n,cmp);
rg int lat=1e9,tmp=0,haha=0;
for(rg int i=1;i<=n+1;i++){
rg int now=id[i];
if(a[now]==lat){
updat(now);
continue;
}
tim++,tmp=0,haha=0;
for(rg int j=1;j<=tp;j++){
if(du[sta[j]]<=1) q.push(sta[j]),vis[sta[j]]=tim,tmp++;
}
while(!q.empty()){
rg int tmp1=q.front();q.pop();
for(rg int j=0;j<g2[tmp1].size();j++){
rg int u=g2[tmp1][j];
if(vis[u]!=tim){
du[u]--;
if(du[u]==1){
vis[u]=tim,tmp++;
q.push(u);
}
}
}
}
for(rg int j=1;j<=tp;j++){
if(vis[sta[j]]==tim) continue;
for(rg int k=0;k<g[sta[j]].size();k++){
rg int u=g[sta[j]][k];
if(vis[u]==tim) continue;
bing(sta[j],u);
}
}
cnt+=tp-tmp;
if(maxsiz>m) break;
if(cnt<=1) ans=std::max(ans,maxsiz),haha=1;
for(rg int j=1;j<=tp;j++){
for(rg int k=0;k<g[sta[j]].size();k++){
rg int u=g[sta[j]][k];
bing(sta[j],u);
}
}
cnt+=tmp;
if(haha) ans=std::max(ans,std::min(m,siz[zhao(id[1])]));
if(tim==2) ans=std::max(ans,std::min(maxsiz,m));
if(ans==m) break;
lat=a[now],tp=0;
updat(now);
}
printf("%d
",ans);
return 0;
}
C. 收集
分析
暑假集训的时候做过一个类似的题,然而没想起来
有一个结论:(DFS) 序求出后,假设关键点按照 (DFS) 序排序后是 ({a_1,a_2,ldots ,a_k})。
那么所有关键点形成的极小连通子树的边权和的两倍等于 (mathrm{dist}(a_1,a_2)+mathrm{dist}(a_2,a_3)+cdots+mathrm{dist}(a_{k-1},a_k)+mathrm{dist}(a_k,a_1))
所以遇到一个点之后查询它的 (dfn) 序的前驱和后继即可
这道题因为不需要返回出发点
所以答案就是极小连通子树的边权和减去联通块直径
直径拿线段树维护一下就行了
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<set>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e5+5;
struct asd{
int to,nxt,val;
}b[maxn<<1];
int h[maxn],tot=1,n,m;
void ad(rg int aa,rg int bb,rg int cc){
b[tot].to=bb;
b[tot].nxt=h[aa];
b[tot].val=cc;
h[aa]=tot++;
}
int dfn[maxn],dfnc,siz[maxn],son[maxn],dep[maxn],fa[maxn],tp[maxn],vis[maxn],rk[maxn];
long long dis[maxn];
void dfs1(rg int now,rg int lat){
fa[now]=lat;
dep[now]=dep[lat]+1;
siz[now]=1;
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==lat) continue;
dis[u]=dis[now]+b[i].val;
dfs1(u,now);
siz[now]+=siz[u];
if(son[now]==0 || siz[u]>siz[son[now]]) son[now]=u;
}
}
void dfs2(rg int now,rg int top){
tp[now]=top;
dfn[now]=++dfnc;
rk[dfnc]=now;
if(son[now]) dfs2(son[now],top);
for(rg int i=h[now];i!=-1;i=b[i].nxt){
rg int u=b[i].to;
if(u==fa[now] || u==son[now]) continue;
dfs2(u,u);
}
}
int getlca(rg int xx,rg int yy){
while(tp[xx]!=tp[yy]){
if(dep[tp[xx]]<dep[tp[yy]]) std::swap(xx,yy);
xx=fa[tp[xx]];
}
return dep[xx]<dep[yy]?xx:yy;
}
long long getdis(rg int xx,rg int yy){
return dis[xx]+dis[yy]-2LL*dis[getlca(xx,yy)];
}
struct trr{
int l,r,zb,yb;
long long val;
}tr[maxn<<2];
void push_up(rg int da){
if(tr[da<<1].zb==-1){
tr[da].zb=tr[da<<1|1].zb,tr[da].yb=tr[da<<1|1].yb,tr[da].val=tr[da<<1|1].val;
} else if(tr[da<<1|1].zb==-1){
tr[da].zb=tr[da<<1].zb,tr[da].yb=tr[da<<1].yb,tr[da].val=tr[da<<1].val;
} else {
tr[da].zb=tr[da<<1].zb,tr[da].yb=tr[da<<1].yb,tr[da].val=tr[da<<1].val;
rg long long tmp=tr[da<<1|1].val;
if(tmp>tr[da].val) tr[da].zb=tr[da<<1|1].zb,tr[da].yb=tr[da<<1|1].yb,tr[da].val=tmp;
tmp=getdis(tr[da<<1].zb,tr[da<<1|1].zb);
if(tmp>tr[da].val) tr[da].zb=tr[da<<1].zb,tr[da].yb=tr[da<<1|1].zb,tr[da].val=tmp;
tmp=getdis(tr[da<<1].zb,tr[da<<1|1].yb);
if(tmp>tr[da].val) tr[da].zb=tr[da<<1].zb,tr[da].yb=tr[da<<1|1].yb,tr[da].val=tmp;
tmp=getdis(tr[da<<1].yb,tr[da<<1|1].zb);
if(tmp>tr[da].val) tr[da].zb=tr[da<<1].yb,tr[da].yb=tr[da<<1|1].zb,tr[da].val=tmp;
tmp=getdis(tr[da<<1].yb,tr[da<<1|1].yb);
if(tmp>tr[da].val) tr[da].zb=tr[da<<1].yb,tr[da].yb=tr[da<<1|1].yb,tr[da].val=tmp;
}
}
void build(rg int da,rg int l,rg int r){
tr[da].zb=tr[da].yb=-1,tr[da].l=l,tr[da].r=r;
if(l==r) return;
rg int mids=(l+r)>>1;
build(da<<1,l,mids),build(da<<1|1,mids+1,r);
}
void xg(rg int da,rg int wz,rg int op){
if(tr[da].l==tr[da].r){
if(op==1) tr[da].zb=tr[da].yb=wz;
else tr[da].zb=tr[da].yb=-1;
return;
}
rg int mids=(tr[da].l+tr[da].r)>>1;
if(wz<=mids) xg(da<<1,wz,op);
else xg(da<<1|1,wz,op);
push_up(da);
}
long long ans;
#define sit std::set<int>::iterator
std::set<int> s;
int main(){
memset(h,-1,sizeof(h));
n=read(),m=read();
rg int aa,bb,cc;
for(rg int i=1;i<n;i++){
aa=read(),bb=read(),cc=read();
ad(aa,bb,cc),ad(bb,aa,cc);
}
dfs1(1,0);
dfs2(1,1);
rg sit it1,it2;
build(1,1,n);
for(rg int i=1;i<=m;i++){
aa=read();
vis[aa]^=1;
if(vis[aa]){
xg(1,aa,1);
s.insert(dfn[aa]);
if(s.size()>1){
it1=it2=s.upper_bound(dfn[aa]);
if(it1==s.end()) it1=s.begin();
ans+=getdis(rk[*it1],aa);
--it2;
if(it2==s.begin()){
it2=--s.end();
} else {
--it2;
}
ans+=getdis(rk[*it2],aa);
ans-=getdis(rk[*it1],rk[*it2]);
}
} else {
xg(1,aa,-1);
if(s.size()>1){
it1=it2=s.upper_bound(dfn[aa]);
if(it1==s.end()) it1=s.begin();
ans-=getdis(rk[*it1],aa);
--it2;
if(it2==s.begin()){
it2=--s.end();
} else {
--it2;
}
ans-=getdis(rk[*it2],aa);
ans+=getdis(rk[*it1],rk[*it2]);
}
s.erase(dfn[aa]);
}
printf("%lld
",ans-tr[1].val);
}
return 0;
}