今天连续3道题都出锅...无F♂A可说
T1 题意简述:jzoj5775
解题思路:还算简单...
考虑先暴力算出(1,1)的魔音值,然后递推。
发现 (x,y)->(x+1,y) 魔音值增加了1~x行中起始点的数量,减少了x+1~n行中起始点的数量。
(x,y)->(x-1,y) 魔音值增加了x~n行中起始点的数量,减少了1~x-1行中起始点的数量。
(x,y)->(x,y+1) 魔音值增加了1~y列中起始点的数量,减少了y+1~n列中起始点的数量。
(x,y)->(x,y-1) 魔音值增加了y~n列中起始点的数量,减少了1~y-1列中起始点的数量。
发现可以求每行和每列的前缀和,可以把时间复杂度压到O(2n)。
有细心的观众可能会说:z呢?
emmm...由于出题人乱出数据,导致所有数据点的z都默认为1。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define ll long long using namespace std; ll n,m,k,sumx[100001],sumy[100001],sum; int main() { freopen("shuru.in","r",stdin); freopen("shuru.out","w",stdout); scanf("%lld%lld%lld",&n,&m,&k); for(ll i=1;i<=m;i++) { ll u,v,w; scanf("%lld%lld%lld",&u,&v,&w); sumx[u]++; sumy[v]++; sum+=w; } for(ll i=1;i<=n;i++) sum+=sumx[i]*(i-1)+sumy[i]*(i-1); for(ll i=2;i<=n;i++) sumx[i]+=sumx[i-1],sumy[i]+=sumy[i-1]; ll xsum=sum,ysum=sum,mnx=sum,ansx=1,mny=sum,ansy=1; for(ll i=2;i<=n;i++) { xsum+=2*sumx[i-1]-sumx[n]; if(xsum<mnx) mnx=xsum,ansx=i; ysum+=2*sumy[i-1]-sumy[n]; if(ysum<mny) mny=ysum,ansy=i; } printf("%lld\n%lld %lld\n",mnx+mny-sum,ansx,ansy); return 0; }
T2 题意简述:jzoj5776
解题思路:和第一题基本相同。
先dfs求出一个点的结果,同时把每个点的子树大小算出。
然后dfs,每次查询到一个点时修改它与它父亲的子树大小及边权,然后算出这个点的结果。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #define INF 0x3f3f3f3f #define ll long long using namespace std; ll n,mn=INF,pnt,cnt,head[700001],rdc[700001],siz[700001],ans[700001]; struct uio{ ll nxt,to,val; }edge[1400001]; void add(ll x,ll y,ll z) { edge[++cnt].nxt=head[x]; edge[cnt].to=y; edge[cnt].val=z; head[x]=cnt; } ll dfs(ll x,ll fa) { siz[x]=1; ll tmp=0; for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to; if(y==fa) continue; tmp+=dfs(y,x)+edge[i].val*siz[y]; siz[x]+=siz[y]; } return tmp; } void dt(ll x,ll fa) { for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to; if(y==fa) continue; ans[y]=ans[x]-edge[i].val*siz[y]; siz[x]-=siz[y],siz[y]+=siz[x]; edge[i].val+=rdc[x]-rdc[y]; ans[y]+=edge[i].val*siz[x]; if(ans[y]<mn) mn=ans[y],pnt=y; if(ans[y]==mn&&y<pnt) pnt=y; dt(y,x); siz[y]-=siz[x],siz[x]+=siz[y]; edge[i].val+=rdc[y]-rdc[x]; } } int main() { freopen("yggdrasil.in","r",stdin); freopen("yggdrasil.out","w",stdout); scanf("%lld",&n); for(ll i=1;i<=n;i++) scanf("%lld",&rdc[i]); for(ll i=1;i<n;i++) { ll u,v,w; scanf("%lld%lld%lld",&u,&v,&w); add(u,v,w-rdc[u]); add(v,u,w-rdc[v]); } ans[1]=dfs(1,0),mn=ans[1],pnt=1; dt(1,0); printf("%lld\n%lld\n",pnt,mn); return 0; }
T3 题意简述:jzoj5786
解题思路:很...麻...烦...
倍增LCA+线段树维护 <-- 这是出题人的思路。
由Menteur_Hxy大佬亲身试验,倍增是会T的。
由ErkkiErkko大佬亲身试验,set也是会T的。
由本蒟蒻亲身试验,就算用树剖+线段树,也是会RE的。
......
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<set> #define INF 0x3f3f3f3f using namespace std; int n,m,cnt,tot,head[800001]; int hvyson[800001],fa[800001],siz[800001],dep[800001],top[800001],dfsno[800001],vis[800001],mp[800001]; int num[3200001]; struct uio{ int nxt,to; }edge[1600001]; //set<int> st; //set<int>::iterator it; void add(int x,int y) { edge[++cnt].nxt=head[x]; edge[cnt].to=y; head[x]=cnt; } void dfs1(int x,int f,int depth) { dep[x]=depth; fa[x]=f; siz[x]=1; int maxson=-1; for(int i=head[x];i;i=edge[i].nxt) { int y=edge[i].to; if(y==f) continue; dfs1(y,x,depth+1); siz[x]+=siz[y]; if(siz[y]>maxson) { hvyson[x]=y; maxson=siz[y]; } } } void dfs2(int x,int topf) { dfsno[x]=++tot; mp[tot]=x; top[x]=topf; if(!hvyson[x]) return; dfs2(hvyson[x],topf); for(int i=head[x];i;i=edge[i].nxt) { int y=edge[i].to; if(y==fa[x]||y==hvyson[x]) continue; dfs2(y,y); } } int lca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } return dep[x]<dep[y]? x:y; } void revise(int now,int l,int r,int x,int y) { if(l==r) { num[now]+=y; return; } int mid=(l+r)>>1; if(x<=mid) revise(now<<1,l,mid,x,y); else revise(now<<1|1,mid+1,r,x,y); num[now]=num[now<<1]+num[now<<1|1]; } int query(int now,int l,int r,int x) { if(l==r&&num[now]) return 1; else if(l==r&&!num[now]) return 0; int mid=(l+r)>>1; if(x<=mid) return query(now<<1,l,mid,x); else return query(now<<1|1,mid+1,r,x); } int query1(int now,int l,int r,int L,int R) { if(!num[now]) return INF; if(l==r) return l; if(L<=l&&r<=R) { int mid=(l+r)>>1; if(num[now<<1|1]) return query1(now<<1|1,mid+1,r,L,R); else return query1(now<<1,l,mid,L,R); } int mid=(l+r)>>1; if(mid>=R) return query1(now<<1,l,mid,L,R); else { int tmp=INF; if(num[now<<1|1]) tmp=query1(now<<1|1,mid+1,r,L,R); if(tmp!=INF) return tmp; else return query1(now<<1,l,mid,L,R); } } int query2(int now,int l,int r,int L,int R) { if(!num[now]) return INF; if(l==r) return l; if(L<=l&&r<=R) { int mid=(l+r)>>1; if(num[now<<1]) return query2(now<<1,l,mid,L,R); else return query2(now<<1|1,mid+1,r,L,R); } int mid=(l+r)>>1; if(mid+1<=L) return query2(now<<1|1,mid+1,r,L,R); else { int tmp=INF; if(num[now<<1]) tmp=query2(now<<1,l,mid,L,R); if(tmp!=INF) return tmp; else return query2(now<<1|1,mid+1,r,L,R); } } int main() { freopen("watch.in","r",stdin); freopen("watch.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int u; scanf("%d",&u); add(i+1,u),add(u,i+1); } dfs1(1,0,1),dfs2(1,1); for(int i=1;i<=m;i++) { int u; scanf("%d",&u); if(u>0&&!vis[u]) {revise(1,1,n,dfsno[u],1);vis[u]=1;continue;} else if(u>0&&vis[u]) {revise(1,1,n,dfsno[u],-1);vis[u]=0;continue;} if(!num[1]) {printf("0\n");continue;} u=-u; int c=query(1,1,n,dfsno[u]); if(c) {printf("%d\n",u);continue;} int a=query1(1,1,n,1,dfsno[u]-1); int b=query2(1,1,n,dfsno[u]+1,n); if(a!=INF) a=lca(u,mp[a]); if(b!=INF) b=lca(u,mp[b]); if(b==INF) printf("%d\n",a); else if(a==INF) printf("%d\n",b); else printf("%d\n",(dep[a]>dep[b]? a:b)); // if(u>0&&!vis[u]) {st.insert(dfsno[u]);vis[u]=1;continue;} // else if(u>0&&vis[u]) {st.erase(dfsno[u]);vis[u]=0;continue;} // if(st.empty()) {printf("0\n");continue;} // u=-u; // if(st.count(u)) {printf("%d\n",u);continue;} // it=st.upper_bound(dfsno[u]); // if(it!=st.end()) // { // a=lca(u,mp[*it]); // if(it==st.begin()) // {printf("%d\n",a);continue;} // it--; // b=lca(u,mp[*it]); // printf("%d\n",(dep[a]>dep[b]? a:b)); // continue; // } // it--; // b=lca(u,mp[*it]); // printf("%d\n",b); } return 0; }
原文地址:https://www.cnblogs.com/water-radish/p/9452260.html
时间: 2024-11-02 10:33:44