N o i p Noip Noip模拟?
T1
直接树剖即可
维护各凭本事
我是维护的轻儿子之和,所以细节要多很多
直接维护所有儿子之和似乎好做一些
标记永久化了,但似乎还是跑最慢。。。
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define bg begin
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline ll readll(){
char ch=gc();
ll res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005;
int n,q,in[N],fa[N],top[N],idx[N],d[N],dep[N],siz[N],son[N],dfn,val[N];
ll sval[N];
vector<int> e[N];
#define pll pair<ll,ll>
namespace Seg{
cs int N=::N<<2;
ll s[N],vtag[N],ss[N],stag[N];
int sz[N],sd[N];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void pushup(int u){
s[u]=s[lc]+s[rc]+vtag[u]*sz[u];
ss[u]=ss[lc]+ss[rc]+stag[u]*sd[u];
}
void build(int u,int l,int r){
if(l==r){sz[u]=1,sd[u]=d[idx[l]],s[u]=val[idx[l]],ss[u]=sval[idx[l]];return;}
build(lc,l,mid),build(rc,mid+1,r);
sz[u]=sz[lc]+sz[rc],sd[u]=sd[lc]+sd[rc];
s[u]=s[lc]+s[rc],ss[u]=ss[lc]+ss[rc];
}
inline void pushnow(int u,int kv,int ks){
s[u]+=(ll)kv*sz[u],vtag[u]+=kv;
ss[u]+=(ll)ks*sd[u],stag[u]+=ks;
}
void update(int u,int l,int r,int st,int des,int kv,int ks){
if(st<=l&&r<=des)return pushnow(u,kv,ks);
(st<=mid)&&(update(lc,l,mid,st,des,kv,ks),1);
(mid<des)&&(update(rc,mid+1,r,st,des,kv,ks),1);
pushup(u);
}
pll query(int u,int l,int r,int st,int des){
if(st>des)return pll(0,0);
if(st<=l&&r<=des)return pll(s[u]+ss[u],sd[u]);
ll res=vtag[u]*(min(des,r)-max(st,l)+1),ret=0;pll x;
if(st<=mid){
x=query(lc,l,mid,st,des);
res+=x.fi,ret+=x.se;
}
if(mid<des){
x=query(rc,mid+1,r,st,des);
res+=x.fi,ret+=x.se;
}res+=ret*stag[u];
return pll(res,ret);
}
ll querytag(int u,int l,int r,int p){
if(l==r)return stag[u];
return (p<=mid)?querytag(lc,l,mid,p)+stag[u]:querytag(rc,mid+1,r,p)+stag[u];
}
ll queryval(int u,int l,int r,int p){
if(l==r)return s[u];
return (p<=mid)?queryval(lc,l,mid,p)+vtag[u]:queryval(rc,mid+1,r,p)+vtag[u];
}
ll queryss(int u,int l,int r,int p,ll t){
if(l==r)return ss[u]+t*d[idx[l]];
return (p<=mid)?queryss(lc,l,mid,p,t+stag[u]):queryss(rc,mid+1,r,p,t+stag[u]);
}
void updateval(int u,int l,int r,int p,int k){
s[u]+=k;
if(l==r)return;
(p<=mid)?updateval(lc,l,mid,p,k):updateval(rc,mid+1,r,p,k);
}
void updatesv(int u,int l,int r,int p,int k){
ss[u]+=k;
if(l==r)return;
(p<=mid)?updatesv(lc,l,mid,p,k):updatesv(rc,mid+1,r,p,k);
}
#undef lc
#undef rc
#undef mid
}
inline ll VAL(int x){return Seg::queryval(1,1,n,in[x])+((x==top[x]&&x!=1)?(Seg::querytag(1,1,n,in[fa[x]])):0);}
void pupdate(int u,int v,int k){
int preu=0,prev=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v),swap(preu,prev);
Seg::update(1,1,n,in[top[u]],in[u],k,k);
if(preu)Seg::updateval(1,1,n,in[preu],-k);
if(son[u])Seg::updateval(1,1,n,in[son[u]],k);
preu=top[u],u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v),swap(preu,prev);
Seg::update(1,1,n,in[v],in[u],k,k);
if(preu)Seg::updateval(1,1,n,in[preu],-k);
if(son[u])Seg::updateval(1,1,n,in[son[u]],k);
if(prev)Seg::updateval(1,1,n,in[prev],-k);
if(fa[v]){Seg::updateval(1,1,n,in[fa[v]],k);
if(fa[fa[v]]&&top[fa[v]]==fa[v])Seg::updatesv(1,1,n,in[fa[fa[v]]],k);}
if(v==top[v]&&fa[v])Seg::updatesv(1,1,n,in[fa[v]],k);
}
ll pquery(int u,int v){
int preu=0,prev=0;ll res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v),swap(preu,prev);
res+=Seg::query(1,1,n,in[top[u]]+1,in[u]).fi;
if(son[u])res+=VAL(son[u]);
res+=Seg::queryss(1,1,n,in[top[u]],0);
preu=top[u],u=fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v),swap(preu,prev);
res+=Seg::query(1,1,n,in[v],in[u]).fi;
if(son[u])res+=VAL(son[u]);
if(fa[v])res+=VAL(fa[v]);
if(v==top[v]&&fa[v])res+=Seg::querytag(1,1,n,in[fa[v]]);
return res;
}
void dfs1(int u){
siz[u]=1,dep[u]=dep[fa[u]]+1;
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
if(v==fa[u])continue;
fa[v]=u,dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int tp){
in[u]=++dfn,idx[dfn]=u,top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
if(v==fa[u]||v==son[u])continue;
sval[u]+=val[v],d[u]++,dfs2(v,v);
}
}
int main(){
#ifdef Stargazer
freopen("tx.in","r",stdin);
freopen("my.out","w",stdout);
#endif
n=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
e[u].pb(v),e[v].pb(u);
}
for(int i=1;i<=n;i++)val[i]=read();
dfs1(1),dfs2(1,1);
Seg::build(1,1,n);
q=read();
while(q--){
int op=read(),x=read(),y=read();
if(op==1){
int c=read();
pupdate(x,y,c);
}
else cout<<pquery(x,y)<<'\n';
}
}
T2:
考虑从大到小排序后分成很多段,每段打死一个人
每段显然是每个人先打打选权值最小的一个的血量
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示最后
i
i
i个人打死了
j
j
j个
那么
f
[
i
]
[
j
]
=
min
k
∈
(
i
,
n
]
(
a
k
(
k
−
i
+
1
)
+
f
[
k
+
1
]
[
j
−
1
]
)
f[i][j]=\min_{k\in(i,n]}(a_k(k-i+1)+f[k+1][j-1])
f[i][j]=mink∈(i,n](ak(k−i+1)+f[k+1][j−1])
发现这个可以斜率优化
每次凸包二分即可,复杂度 O ( T n 2 l o g n ) O(Tn^2logn) O(Tn2logn)
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define bg begin
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline ll readll(){
char ch=gc();
ll res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=2005;
int n,m,a[N],f[N][N];
struct pt{
int x,y;
pt(int _x=0,int _y=0):x(_x),y(_y){}
friend inline pt operator +(cs pt &a,cs pt &b){
return pt(a.x+b.x,a.y+b.y);
}
friend inline pt operator -(cs pt &a,cs pt &b){
return pt(a.x-b.x,a.y-b.y);
}
friend inline ll operator *(cs pt &a,cs pt &b){
return 1ll*a.x*b.y-1ll*a.y*b.x;
}
}stk[N];
int top;
inline void push(cs pt &x){
while(top&&stk[top].x==x.x){
if(stk[top].y>x.y)top--;
else return;
}
while(top>1&&(stk[top]-stk[top-1])*(x-stk[top-1])<=0)top--;
stk[++top]=x;
}
inline void solve(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
sort(a+1,a+n+1,greater<int>());
for(int i=1;i<=m;i++){
top=0;
for(int j=n-i+1;j;j--){
push(pt(a[j],f[i-1][j+1]+a[j]*j));
int res=1,l=2,r=top;
while(l<=r){
int mid=(l+r)/2;
if((stk[mid]-stk[mid-1])*(pt(1,j-1))>=0)l=mid+1,res=mid;
else r=mid-1;
}
f[i][j]=stk[res].y-stk[res].x*(j-1);
}
}
cout<<f[m][1]<<'\n';
}
int main(){
int T=read();
while(T--)solve();
}
T3
之前
c
s
p
csp
csp模拟似乎考过一道一模一样的。。。
先不考虑
k
k
k
考虑对有贡献的关键点
D
P
DP
DP
f
[
i
]
f[i]
f[i]表示当前结尾为
i
i
i的答案
那么
f
[
i
]
=
max
j
,
j
<
i
,
a
j
<
a
i
,
a
i
−
i
≤
a
j
−
j
f
j
+
1
f[i]=\max_{j,j<i,a_j<a_i,a_i-i\le a_j-j}f_j+1
f[i]=maxj,j<i,aj<ai,ai−i≤aj−jfj+1
考虑有三个限制
如果按照
a
i
−
i
a_i-i
ai−i排序后,如果
i
i
i前面有
j
j
j满足
b
i
>
b
j
b_i>b_j
bi>bj,那么必有
i
>
j
i>j
i>j
于是树状数组即可
考虑存在 k k k即答案不可能超过 n − k , a i − i < k n-k,a_i-i<k n−k,ai−i<k判一下即可
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define pii pair<int,int>
#define bg begin
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline ll readll(){
char ch=gc();
ll res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=500005;
int n;
namespace bit{
int tr[N];
#define lb(x) (x&(-x))
void update(int p,int k){
for(;p<=n;p+=lb(p))chemx(tr[p],k);
}
int query(int p,int res=0){
for(;p>0;p-=lb(p))chemx(res,tr[p]);return res;
}
}
int k;
pii a[N];
inline bool comp(cs pii &x,cs pii &y){return (x.fi-x.se)==(y.fi-y.se)?(x.se<y.se):(x.fi-x.se>y.fi-y.se);}
int main(){
n=read(),k=read();int ans=0;
for(int i=1;i<=n;i++)a[i]=pii(read(),i);
sort(a+1,a+n+1,comp);
for(int i=1;i<=n;i++)if(a[i].fi<=a[i].se&&a[i].se-a[i].fi<=k&&a[i].fi<=n-k){
int now=bit::query(a[i].fi-1)+1;
bit::update(a[i].fi,now);
chemx(ans,now);
}
cout<<min(ans,n-k)<<'\n';
return 0;
}