T 1 T_1 T1——gxc(3830)
Description:
有一个长度为
n
n
n的序列
A
A
A,假如有将该序列划分成
m
m
m个区间,满足每个区间排序后序列
A
A
A是有序的,求最大的
m
m
m。
n
≤
200000
,
1
≤
A
i
≤
1
0
9
n\le 200000,1\le A_i\le 10^9
n≤200000,1≤Ai≤109
Solution:
- 这题有许多解法,有 Θ ( n ) \Theta(n) Θ(n)的什么前缀最小值,后缀最大值,也可以是 Θ ( n log n ) \Theta(n\log n) Θ(nlogn)排序,离散。
- 总之,这类题还是需要考试时模拟发现一定的规律或结论,才能进一步的解题。
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
const int N=200005;
int n,m;
int A[N],B[N],last[N];
int main(){
// freopen("gxc.in","r",stdin);
// freopen("gxc.out","w",stdout);
scanf("%d",&n);
REP(i,1,n) scanf("%d",&A[i]),B[i]=A[i];
sort(B+1,B+n+1);
m=unique(B+1,B+n+1)-B;
REP(i,1,n){
A[i]=lower_bound(B+1,B+m+1,A[i])-B-1;
last[A[i]]=i;
}
int ans=0;
int j=1,k=0,Mx=0;
REP(i,1,n){
chkmax(Mx,A[i]);
while(k<Mx)chkmax(j,last[k]),++k;
if(i>=j) ++ans;
}
printf("%d\n",ans);
return 0;
}
T 2 T_2 T2——story(1780)
Description:
有一个长度为
n
n
n的序列
A
A
A,且
A
i
∈
[
1
,
K
]
A_i \in[1,K]
Ai∈[1,K]。
现在有m个操作,有2种操作:
1
x
x
x
v
v
v表示将位置
A
x
A_x
Ax改为
v
v
v;
2 输出最短的区间长度,满足该区间包含
[
1
,
K
]
[1,K]
[1,K]的数。
n
,
m
≤
50000
,
K
≤
30
n,m\le 50000,K\le 30
n,m≤50000,K≤30
Solution:
- 对于 Θ ( n m ) \Theta(nm) Θ(nm)的做法,是用单调性来维护。
- 而发现 K K K的范围比较小,那么不难猜到正解的复杂度是 Θ ( m K log n ) \Theta(mK\log n) Θ(mKlogn)
- 因为带修改且实时询问的数据结构,我们很容易会想到用线段树。
- 但是呢,这个合并不是直接合并的。
- 对于每种数,我们需要记录左区间的最后一次出现的序列的位置,以及右区间的第一次的出现的序列的位置。
- 这样,再类似于 Θ ( n m ) \Theta(nm) Θ(nm)的单调性即可合并。
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
template<class T>inline void rd(T&x){
char c;x=0;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
const int N=50002,M=32,INF=0x3f3f3f3f;
int n,m,q;
int A[N];
int cnt[M];
struct p20{
void solve(){
while(q--){
int op,x,v;scanf("%d",&op);
if(op==1){
scanf("%d%d",&x,&v);
A[x]=v;
}
else {
int ans=-1;
REP(len,m,n){
REP(l,1,n-len+1){
int r=l+len-1;
memset(cnt,0,sizeof cnt);
REP(i,l,r) cnt[A[i]]++;
bool flag=1;
REP(i,1,m) if(!cnt[i]) {flag=0;break;}
if(flag) {
ans=len;
goto loop;
}
}
}
loop:;
printf("%d\n",ans);
}
}
}
}p1;
struct p50{
bool check(){
REP(i,1,m) if(!cnt[i])return 0;
return 1;
}
int work(){
int ans=INF;
memset(cnt,0,sizeof cnt);
int R=0,L=1;
REP(i,1,n){
R++;
cnt[A[R]]++;
while(L<R and cnt[A[L]]>1)cnt[A[L]]--,L++;
if(check()) chkmin(ans,R-L+1);
}
return ans==INF?-1:ans;
}
void solve(){
while(q--){
int op,x,v;
scanf("%d",&op);
if(op==1){
scanf("%d%d",&x,&v);
A[x]=v;
}
else printf("%d\n",work());
}
}
}p2;
int mark1[M],mark2[M];
struct p100{
struct Tree{
#define lson L,mid,p<<1
#define rson mid+1,R,p<<1|1
#define family tree[p],tree[p<<1],tree[p<<1|1]
struct node{
int L,R;
int len,num;
int mn[M],mx[M];
}tree[N<<2];
void Up(node &P,node L,node R){
int sz1=0,sz2=0;
SREP(i,0,L.num){
P.mn[sz1++]=L.mn[i];
mark1[A[L.mn[i]]]=1;
}
SREP(i,0,R.num){
P.mx[sz2++]=R.mx[i];
mark2[A[R.mx[i]]]=1;
if(mark1[A[R.mn[i]]])continue;
P.mn[sz1++]=R.mn[i];
}
SREP(i,0,L.num){
if(mark2[A[L.mx[i]]])continue;
P.mx[sz2++]=L.mx[i];
}
P.num=sz1;
chkmin(P.len=L.len,R.len);
memset(mark1,0,sizeof mark1);
memset(mark2,0,sizeof mark2);
if(sz1<m){
P.len=INF;
return;
}
int can=L.num,id=0;
SREP(i,0,L.num) mark1[A[L.mx[i]]]++;
DREP(i,L.num-1,0){
while(can<m and id<R.num){
if(!mark1[A[R.mn[id]]])can++;
mark1[A[R.mn[id]]]++;
id++;
}
if(can<m)break;
if(id) chkmin(P.len,R.mn[id-1]-L.mx[i]+1);
mark1[A[L.mx[i]]]--;
if(!mark1[A[L.mx[i]]]) can--;
}
memset(mark1,0,sizeof mark1);
}
void build(int L,int R,int p){
tree[p].L=L,tree[p].R=R;
tree[p].len=INF;
if(L==R){
if(m==1)tree[p].len=1;
tree[p].mn[0]=L;
tree[p].mx[0]=L;
tree[p].num=1;
return;
}
int mid=(L+R)>>1;
build(lson),build(rson);
Up(family);
}
void update(int x,int p,int v){
if(tree[p].L==tree[p].R){
A[x]=v;
return;
}
int mid=(tree[p].L+tree[p].R)>>1;
if(x<=mid)update(x,p<<1,v);
else update(x,p<<1|1,v);
Up(family);
}
}T;
void solve(){
T.build(1,n,1);
while(q--){
int op,x,v;
rd(op);
if(op==1) rd(x),rd(v),T.update(x,1,v);
else printf("%d\n",T.tree[1].len==INF?-1:T.tree[1].len);
}
}
}p3;
int main(){
// freopen("story.in","r",stdin);
// freopen("story.out","w",stdout);
rd(n),rd(m),rd(q);
REP(i,1,n) rd(A[i]);
if(n<=300 and q<=300) p1.solve();
else if(n<=5000 and q<=5000) p2.solve();
else p3.solve();
return 0;
}
T 3 T_3 T3——farm(3060)
Description:
一棵树,有
q
q
q个询问,每次询问以
x
x
x为中心,建
y
y
y条河,满足河一定与
x
x
x连通,求每次询问的最大价值(河覆盖的路径长度)。
n
,
q
≤
1
0
5
n,q\le 10^5
n,q≤105
Solution:
- 首先,我们可以得到一个定理:
- 对于一个无根树,如果它有 2 k 2k 2k个叶子节点,我们只用 k k k条路径就足以将其覆盖。所以我们就可以把问题变为:在无根树中找 2 y 2y 2y个叶子节点,是其形成一个包含点x的边权最大连通块 S S S。
- 也就是说我们以 x x x为根节点,找 2 y 2y 2y个叶子节点,使它们到形成的 S S S最大。
- 而模拟发现,我们把这些叶子节点产生的贡献 v a l val val,选出最大的 2 y − 1 2y-1 2y−1个即为答案。
- 但是对于每个询问的 x x x都是不同的。
- 然后,我们可以发现对于每次询问, S S S中一定会至少包含此树直径中的两端点之一。
- 所以我们可以分别以直径两端点为根节点的树中找最大的 2 y − 1 2y−1 2y−1个叶子节点的 v a l val val之和。
- 但是这样就又有一个问题了,那就是这样写会导致 x x x可能不在 S S S之中。
- 但这并不碍事,我们可以将其中一条最小的删掉,来连向 x x x。
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
const int N=1e5+2,S=20;
int n,q;
int qwq,head[N];
struct edge{
int to,nxt;
int w;
}E[N<<1];
void addedge(int x,int y,int z){E[qwq]=(edge){y,head[x],z};head[x]=qwq++;}
#define EREP(x) for(int i=head[x];~i;i=E[i].nxt)
int Mx,Id;
void dfs(int x,int f,int dis){
if(chkmax(Mx,dis)) Id=x;
EREP(x){
int y=E[i].to;
if(y==f)continue;
dfs(y,x,dis+E[i].w);
}
}
int val_cmp[N];
bool cmp(int x,int y){return val_cmp[x]>val_cmp[y];}
struct node{
int rt;
int far[N],dis[N];
int fa[N][S];
int cnt,leaf[N],val[N],sum[N],id[N];
void dfs1(int x,int f){
fa[x][0]=f;
bool child=0;
EREP(x){
int y=E[i].to;
if(y==f)continue;
child=1;
dis[y]=dis[x]+E[i].w;
dfs1(y,x);
if(dis[far[x]]<dis[far[y]]) far[x]=far[y];
}
if(!child)leaf[++cnt]=x,far[x]=x;
}
void dfs2(int x,int v){
val[x]=v;
EREP(x){
int y=E[i].to;
if(y==fa[x][0])continue;
if(far[x]==far[y]) dfs2(y,v+E[i].w);
else dfs2(y,E[i].w);
}
}
void init(){
dfs1(rt,0);
SREP(j,1,S) REP(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];
dfs2(rt,0);
memcpy(val_cmp,val,sizeof val_cmp);
sort(leaf+1,leaf+1+cnt,cmp);
REP(i,1,cnt) id[leaf[i]]=i,sum[i]=sum[i-1]+val[leaf[i]];
}
int solve(int x,int y){
if(y>=cnt) return sum[cnt];
if(y>=id[far[x]]) return sum[y];
int t=far[x];
DREP(i,S-1,0) if(fa[x][i] and id[far[fa[x][i]]]>y) x=fa[x][i];
x=fa[x][0];
return sum[y]+dis[t]-dis[x]-min(dis[far[x]]-dis[x],val[leaf[y]]);
}
}A,B;
void Init(){
Mx=0;
dfs(1,0,0);
A.rt=Id;
Mx=0;
dfs(Id,0,0);
B.rt=Id;
A.init();
B.init();
}
int main(){
// freopen("farm.in","r",stdin);
// freopen("farm.out","w",stdout);
scanf("%d%d",&n,&q);
memset(head,-1,sizeof head);
SREP(i,1,n){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
}
Init();
while(q--){
int x,y;
scanf("%d%d",&x,&y);
y=y*2-1;
int ans=0;
chkmax(ans,max(A.solve(x,y),B.solve(x,y)));
printf("%d\n",ans);
}
return 0;
}