2021.8.15考试总结[NOIP模拟40]

T1 送花


线段树。枚举右端点,线段树记录左端点对应的值。

每次对当前颜色上上次出现的位置到上次出现的位置区间减,上次出现的位置到当前位置区间加。

$code:$

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const int NN=1e6+5;
 5 int n,m,c[NN],d[NN],pre[NN][2];
 6 LL ans;
 7 inline int read(){
 8     int x=0,f=1; char ch=getchar();
 9     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
10     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
11     return x*f;
12 }
13 inline void write(LL x,char sp){
14     char ch[20]; int len=0;
15     if(x<0){ putchar('-'); x=~x+1; }
16     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
17     for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
18 }
19 struct segment_tree{
20     #define ld rt<<1
21     #define rd (rt<<1)|1
22     LL mx[NN<<2],laz[NN<<2];
23     void pushup(int rt){
24         mx[rt]=max(mx[ld],mx[rd]);
25     }
26     void pushdown(int rt){
27         if(!laz[rt]) return;
28         laz[ld]+=laz[rt]; laz[rd]+=laz[rt];
29         mx[ld]+=laz[rt]; mx[rd]+=laz[rt];
30         laz[rt]=0;
31     }
32     void modify(int rt,int l,int r,int opl,int opr,int val){
33         if(l>=opl&&r<=opr){
34             mx[rt]+=val;
35             laz[rt]+=val;
36             return;
37         }
38         pushdown(rt);
39         int mid=(l+r)>>1;
40         if(opl<=mid) modify(ld,l,mid,opl,opr,val);
41         if(opr>mid) modify(rd,mid+1,r,opl,opr,val);
42         pushup(rt);
43     }
44     LL query(int rt,int l,int r,int opl,int opr){
45         if(l>=opl&&r<=opr) return mx[rt];
46         pushdown(rt);
47         int mid=(l+r)>>1;
48         LL ans=0;
49         if(opl<=mid) ans=max(ans,query(ld,l,mid,opl,opr));
50         if(opr>mid) ans=max(ans,query(rd,mid+1,r,opl,opr));
51         return ans;
52     }
53 }s;
54 signed main(){
55     n=read(); m=read();
56     for(int i=1;i<=n;i++) c[i]=read();
57     for(int i=1;i<=m;i++) d[i]=read();
58     for(int i=1;i<=n;i++){
59         if(pre[c[i]][0]) s.modify(1,1,n,pre[c[i]][1]+1,pre[c[i]][0],-d[c[i]]);
60         s.modify(1,1,n,pre[c[i]][0]+1,i,d[c[i]]);
61         ans=max(ans,s.query(1,1,n,1,n));
62         pre[c[i]][1]=pre[c[i]][0]; pre[c[i]][0]=i; 
63     }
64     write(ans,'\n');
65     return 0;
66 }
T1

T2 星空


并查集合并距离为零的点,$O(n^2)$有$70pts$。

考虑优化。发现令$b=x+y$,$B=x-y$,那么两个点的直接距离其实为$min(|b_i-b_j|,|B_i-B_j|)$。

于是可以排序后扫一遍得出答案。点对数只要去重后将两个符合条件的并查集大小相乘后累加。

注意排序后点集的下标改变,所有并查集操作都要通过$id$来实现。

$code:$

 1 #include<bits/stdc++.h>
 2 #define mp make_pair
 3 using namespace std;
 4 const int NN=1e5+5;
 5 int n,x[NN],y[NN],fa[NN],siz[NN],ans=INT_MAX,num;
 6 map<pair<int,int>,bool>vis;
 7 vector<pair<int,int> >vec;
 8 struct loc{ int x,y,b1,b2,id; }l[NN];
 9 inline bool cmp1(loc a,loc b){ return a.b1<b.b1; }
10 inline bool cmp2(loc a,loc b){ return a.b2<b.b2; }
11 inline int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }
12 inline int read(){
13     int x=0,f=1; char ch=getchar();
14     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
15     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
16     return x*f;
17 }
18 inline void write(int x,char sp){
19     char ch[20]; int len=0;
20     if(x<0){ putchar('-'); x=~x+1; }
21     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
22     for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp);
23 }
24 void merge(int x,int y){
25     x=getfa(x); y=getfa(y);
26     if(x==y) return;
27     fa[y]=x; siz[x]+=siz[y];
28 }
29 signed main(){
30     n=read();
31     for(int i=1;i<=n;i++){ 
32         l[i].x=read(); l[i].y=read();
33         fa[i]=i; siz[i]=1; l[i].id=i;
34         l[i].b1=l[i].y-l[i].x;
35         l[i].b2=l[i].y+l[i].x;
36     }
37     sort(l+1,l+n+1,cmp1);
38     for(int i=1;i<n;i++)
39         if(l[i].b1==l[i+1].b1) merge(l[i].id,l[i+1].id);
40     sort(l+1,l+n+1,cmp2);
41     for(int i=1;i<n;i++)
42         if(l[i].b2==l[i+1].b2) merge(l[i].id,l[i+1].id);
43     sort(l+1,l+n+1,cmp1);
44     for(int i=1;i<n;i++){
45         if(getfa(l[i].id)==getfa(l[i+1].id)) continue;
46         if(l[i+1].b1==l[i].b1) continue;
47         if(ans>=l[i+1].b1-l[i].b1){
48             if(ans>l[i+1].b1-l[i].b1) vec.clear();
49             vec.push_back(mp(getfa(l[i].id),getfa(l[i+1].id)));
50             ans=l[i+1].b1-l[i].b1;
51         }
52     }
53     sort(l+1,l+n+1,cmp2);
54     for(int i=1;i<n;i++){
55         if(getfa(l[i].id)==getfa(l[i+1].id)) continue;
56         if(l[i+1].b2==l[i].b2) continue;
57         if(ans>=l[i+1].b2-l[i].b2){
58             if(ans>l[i+1].b2-l[i].b2) vec.clear();
59             vec.push_back(mp(getfa(l[i].id),getfa(l[i+1].id)));
60             ans=l[i+1].b2-l[i].b2;
61         }
62     }
63     if(vec.empty()){ puts("0"); return 0;}
64     for(int i=0;i<vec.size();i++){
65         if(vis[vec[i]]) continue;
66         vis[vec[i]]=1;
67         vis[mp(vec[i].second,vec[i].first)]=1;
68         num+=siz[vec[i].first]*siz[vec[i].second];
69     }
70     write(ans,'\n'); write(num,'\n');
71     return 0;
72 }
T2

 T3 零一串


因为不可抗力詁了(连咕两场的怠惰罪该万死

posted @ 2021-08-16 06:20  keen_z  阅读(27)  评论(0编辑  收藏  举报