2021.7.29考试总结[NOIP模拟27]

T1 牛半仙的妹子图


做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数。

我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm挺优秀。

后来发现wlr都是1e9,一个个求前缀和直接炸了,考场上感觉l,r,w差值对答案有影响就没离散化,开了个map记出现的w的前缀和,其他都能O1计算。

这不切了吗?年轻的我如是想到。

于是我领略到了map80倍常数的威力。离散化开数组再带到初值计算就A了。

考场拿了75pts还WA了仨点,据WTZ说要大力分类讨论,但我改对离散化直接切了,不大懂。

code:

 1 #include<bits/stdc++.h>
 2 #define debug exit(0)
 3 #define int long long
 4 #define rin register signed
 5 using namespace std;
 6 const int NN=5e5+5;
 7 struct edge{
 8     int st,to,nex,w;
 9 }e[NN];
10 struct bcj{
11     int fa;
12     bitset<650>gl;
13 }p[NN];
14 int n,m,q,x,M,opt,head[NN],num,c[NN],ans,maxr,l[10005],r[10005];
15 int has[NN],ext,pre[NN],ts[NN];
16 inline bool cmp(edge a,edge b){ return a.w<b.w; }
17 inline int getfa(int a){ return p[a].fa==a?a:p[a].fa=getfa(p[a].fa); }
18 inline int read(){
19     int x=0,f=1;
20     char ch=getchar();
21     while(ch<'0'||ch>'9'){
22         if(ch=='-') f=-1;
23         ch=getchar();
24     }
25     while(ch>='0'&&ch<='9'){
26         x=(x<<1)+(x<<3)+(ch^48);
27         ch=getchar();
28     }
29     return x*f;
30 }
31 void write(int x){
32     if(x<0) putchar('-'), x=-x;
33     if(x>9) write(x/10);
34     putchar(x%10+'0');
35 }
36 void lsh(){
37     for(int i=1;i<=m;i++) has[i]=e[i].w;
38     ext=unique(has+1,has+1+m)-has-1;
39     for(int i=1;i<=m;i++)
40         e[i].w=lower_bound(has+1,has+ext+1,e[i].w)-has;
41 }
42 inline void add(int a,int b,int d){
43     e[++num].to=b; e[num].nex=head[a]; head[a]=num; e[num].w=d; e[num].st=a;
44 }
45 void gather(int a,int b){
46     a=getfa(a); b=getfa(b);
47     if(a==b) return;
48     p[b].fa=a; p[a].gl|=p[b].gl;
49 }
50 signed main(){
51     n=read(); m=read(); q=read(); x=read(); opt=read(); ts[0]=1;
52     if(opt) M=read();
53     for(rin i=1;i<=n;i++){ 
54         c[i]=read();
55         p[i].fa=i; p[i].gl[c[i]]=1;
56     }
57     for(rin i=1;i<=m;i++){
58         int u=read(),v=read(),w=read();
59         add(u,v,w);
60     } sort(e+1,e+m+1,cmp);
61     lsh();
62     for(rin i=1;i<=m;i++){
63         int u=e[i].st,v=e[i].to;
64         gather(u,v);
65         if(e[i].w!=e[i+1].w){ 
66             ts[e[i].w]=p[getfa(x)].gl.count();
67             pre[e[i].w]=pre[e[i].w-1]+ts[e[i].w-1]*(has[e[i].w]-has[e[i].w-1]-1);
68             pre[e[i].w]+=ts[e[i].w];
69         }
70     }
71     for(rin i=1;i<=q;i++){
72         int l=read(),r=read();
73         if(opt) l=(l^ans)%M+1, r=(r^ans)%M+1;
74         if(l>r) swap(l,r); l--;
75         int wl=upper_bound(has,has+ext+1,l)-has-1;
76         int wr=upper_bound(has,has+ext+1,r)-has-1;
77         ans=pre[wr]+ts[wr]*(r-has[wr]);
78         ans-=pre[wl]+ts[wl]*(l-has[wl]);
79         write(ans); putchar('\n');
80     }
81     return 0;
82 }
T1

 

T2 牛半仙的妹子tree


考场暴力炸了,只有10pts。

题解里正解好像是分块,好像还能点分树,机房里还看到了很多奇奇怪怪的AC代码,

但最快的竟然是求LCA暴力判断就离谱。

记录染色的点和染色的时间,查询时枚举比较时间差和距离即可。

树剖竟然只400多ms?

code:

 1 #include<bits/stdc++.h>
 2 #define debug exit(0)
 3 #define ii pair<int,int>
 4 #define mp make_pair
 5 #define fi first
 6 #define se second
 7 #define pb push_back
 8 using namespace std;
 9 const int NN=1e5+5;
10 int n,m,x,to[NN<<1],nex[NN<<1],head[NN],opt,num;
11 int dep[NN],son[NN],siz[NN],dfn[NN],id[NN],fa[NN],top[NN],cnt;
12 vector<ii>t;
13 inline int read(){
14     int x=0,f=1;
15     char ch=getchar();
16     while(ch<'0'||ch>'9'){
17         if(ch=='-') f=-1;
18         ch=getchar();
19     }
20     while(ch>='0'&&ch<='9'){
21         x=(x<<1)+(x<<3)+(ch^48);
22         ch=getchar();
23     }
24     return x*f;
25 }
26 void write(int x){
27     if(x<0) putchar('-'), x=-x;
28     if(x>9) write(x/10);
29     putchar(x%10+'0');
30 }
31 inline void add(int a,int b){
32     to[++num]=b; nex[num]=head[a]; head[a]=num;
33     to[++num]=a; nex[num]=head[b]; head[b]=num;
34 }
35 void dfs1(int f,int s){
36     fa[s]=f; dep[s]=dep[f]+1; siz[s]=1;
37     for(int i=head[s];i;i=nex[i]){
38         int v=to[i];
39         if(v==f) continue;
40         dfs1(s,v);
41         siz[s]+=siz[v];
42         if(siz[v]>siz[son[s]]) son[s]=v;
43     }
44 }
45 void dfs2(int s,int t){
46     top[s]=t; dfn[s]=++cnt; id[cnt]=s;
47     if(!son[s]) return;
48     dfs2(son[s],t);
49     for(int i=head[s];i;i=nex[i]){
50         int v=to[i];
51         if(v!=son[s]&&v!=fa[s]) dfs2(v,v);
52     }
53 }
54 inline int LCA(int x,int y){
55     int fx=top[x],fy=top[y];
56     while(fx!=fy)
57         if(dep[fx]<dep[fy]) y=fa[fy], fy=top[y];
58         else x=fa[fx], fx=top[x];
59     return dep[x]>dep[y]?y:x;
60 }
61 inline bool check(int x,int ti){
62     for(int j=0;j<t.size();j++)
63         if(dep[x]+dep[t[j].fi]-2*dep[LCA(x,t[j].fi)]<=ti-t[j].se)
64             return 0;
65     return 1;
66 }
67 signed main(){
68     n=read(); m=read();
69     for(int i=1;i<n;i++) add(read(),read());
70     dfs1(0,1); dfs2(1,1);
71     for(int i=1;i<=m;i++){
72         opt=read(); x=read();
73         if(opt==1) if(check(x,i)) t.pb(mp(x,i));
74         if(opt==2) t.clear();
75         if(opt==3) puts(check(x,i)?"orzFsYo":"wrxcsd");
76     }
77     return 0;
78 }
T2

upd:一个链一个菊花直接把RMQ跟树剖卡废了。考虑赵sir的神仙线段树。

一个点u被v染色,要满足$dep_{u}+dep_{v}-2\times dep_{lca_{u,v}}<=now-time_{v}$,移个项可得$time_{v}+dep_{v}-2\times dep_{lca_{u,v}}<=now-dep_{u}$。

在线段树中维护等式左边的最小值,每次修改向上修改到根,查询时也跳链比较等式左右即可。清空直接打标记。

code:

  1 #include<bits/stdc++.h>
  2 #define debug exit(0)
  3 #define ld rt<<1
  4 #define rd (rt<<1)|1
  5 using namespace std;
  6 const int NN=1e5+5,inf=2e9;
  7 int n,m,x,to[NN<<1],nex[NN<<1],head[NN],opt,num;
  8 int dep[NN],son[NN],siz[NN],dfn[NN],id[NN],fa[NN],top[NN],cnt;
  9 inline int read(){
 10     int x=0,f=1;
 11     char ch=getchar();
 12     while(ch<'0'||ch>'9'){
 13         if(ch=='-') f=-1;
 14         ch=getchar();
 15     }
 16     while(ch>='0'&&ch<='9'){
 17         x=(x<<1)+(x<<3)+(ch^48);
 18         ch=getchar();
 19     }
 20     return x*f;
 21 }
 22 void write(int x){
 23     if(x<0) putchar('-'), x=-x;
 24     if(x>9) write(x/10);
 25     putchar(x%10+'0');
 26 }
 27 inline void add(int a,int b){
 28     to[++num]=b; nex[num]=head[a]; head[a]=num;
 29     to[++num]=a; nex[num]=head[b]; head[b]=num;
 30 }
 31 void dfs1(int f,int s){
 32     fa[s]=f; dep[s]=dep[f]+1; siz[s]=1;
 33     for(int i=head[s];i;i=nex[i]){
 34         int v=to[i];
 35         if(v==f) continue;
 36         dfs1(s,v);
 37         siz[s]+=siz[v];
 38         if(siz[v]>siz[son[s]]) son[s]=v;
 39     }
 40 }
 41 void dfs2(int s,int t){
 42     top[s]=t; dfn[s]=++cnt; id[cnt]=s;
 43     if(!son[s]) return;
 44     dfs2(son[s],t);
 45     for(int i=head[s];i;i=nex[i]){
 46         int v=to[i];
 47         if(v!=son[s]&&v!=fa[s]) dfs2(v,v);
 48     }
 49 }
 50 struct segment_tree{
 51     int l[NN<<2],r[NN<<2],mn[NN<<2],laz[NN<<2],lzc[NN<<2];
 52     void pushup(int rt){
 53         if(l[rt]==r[rt]) return;
 54         mn[rt]=min(mn[ld],mn[rd]);
 55     }
 56     void pushdown(int rt){
 57         if(l[rt]==r[rt]) return;
 58         if(lzc[rt]){
 59             mn[ld]=inf; mn[rd]=inf;
 60             laz[ld]=laz[rd]=0;
 61             lzc[ld]=lzc[rd]=1; lzc[rt]=0; 
 62         }
 63         if(laz[rt]){
 64             mn[ld]=min(mn[ld],laz[rt]-2*dep[id[r[ld]]]);
 65             mn[rd]=min(mn[rd],laz[rt]-2*dep[id[r[rd]]]);
 66             if(!laz[ld]) laz[ld]=laz[rt];
 67             else laz[ld]=min(laz[ld],laz[rt]);
 68             if(!laz[rd]) laz[rd]=laz[rt];
 69             else laz[rd]=min(laz[rd],laz[rt]);
 70             laz[rt]=0;
 71         }
 72     }
 73     void build(int rt,int opl,int opr){
 74         l[rt]=opl; r[rt]=opr; mn[rt]=inf;
 75         if(opl==opr) return;
 76         int mid=opl+opr>>1;
 77         build(ld,opl,mid); build(rd,mid+1,opr);
 78     }
 79     void update(int rt,int opl,int opr,int val){
 80         if(l[rt]>=opl&&r[rt]<=opr){
 81             if(val!=inf){
 82                 mn[rt]=min(mn[rt],val-2*dep[id[r[rt]]]);
 83                 if(!laz[rt]) laz[rt]=val;
 84                 else laz[rt]=min(laz[rt],val);
 85             }
 86             else{ mn[rt]=inf; laz[rt]=0; lzc[rt]=1; }
 87             return;
 88         }
 89         pushdown(rt);
 90         int mid=l[rt]+r[rt]>>1;
 91         if(opl<=mid) update(ld,opl,opr,val);
 92         if(opr>mid) update(rd,opl,opr,val);
 93         pushup(rt);
 94     }
 95     int query(int rt,int opl,int opr){
 96         if(l[rt]>=opl&&r[rt]<=opr) return mn[rt];
 97         pushdown(rt);
 98         int mid=l[rt]+r[rt]>>1,ans=inf;
 99         if(opl<=mid) ans=min(ans,query(ld,opl,opr));
100         if(opr>mid) ans=min(ans,query(rd,opl,opr));
101         return ans;
102     }
103 }s;
104 void UPD(int x,int val){
105     int fx=top[x];
106     val=val+dep[x];
107     while(fx!=1){
108         s.update(1,dfn[fx],dfn[x],val);
109         x=fa[fx]; fx=top[x];
110     }
111     s.update(1,1,dfn[x],val);
112 }
113 void SOL(int x,int val){
114     int fx=top[x];
115     val=val-dep[x];
116     while(fx!=1){
117         if(s.query(1,dfn[fx],dfn[x])<=val){
118             puts("wrxcsd");
119             return;
120         }
121         x=fa[fx]; fx=top[x];
122     }
123     if(s.query(1,1,dfn[x])<=val) puts("wrxcsd");
124     else puts("orzFsYo");
125 }
126 int main(){
127     n=read(); m=read();
128     for(int i=1;i<n;i++) add(read(),read());
129     dfs1(0,1); dfs2(1,1); s.build(1,1,n);
130     for(int i=1;i<=m;i++){
131         opt=read(); x=read();
132         if(opt==1) UPD(x,i);
133         if(opt==2) s.update(1,1,n,inf);
134         if(opt==3) SOL(x,i);
135     }
136     return 0;
137 }
T2线段树

 

 

T3 牛半仙的妹子序列


一眼极长上升子序列。

但不会。

于是又回顾了一遍god knows(模拟16),还是不大懂,整了挺久。但好像几乎一模一样。

把求最小权的步骤换成求方案数就完了。

code:

 1 #include<bits/stdc++.h>
 2 #define debug exit(0)
 3 #define int long long
 4 #define ld rt<<1
 5 #define rd (rt<<1)|1
 6 using namespace std;
 7 const int p=998244353,NN=2e5+5;
 8 int n,bty[NN],ans;
 9 inline int read(){
10     int x=0,f=1;
11     char ch=getchar();
12     while(ch<'0'||ch>'9'){
13         if(ch=='-') f=-1;
14         ch=getchar();
15     }
16     while(ch>='0'&&ch<='9'){
17         x=(x<<1)+(x<<3)+(ch^48);
18         ch=getchar();
19     }
20     return x*f;
21 }
22 void write(int x){
23     if(x<0) putchar('-'), x=-x;
24     if(x>9) write(x/10);
25     putchar(x%10+'0');
26 }
27 struct segment_tree{
28     int mx[NN<<2],sum[NN<<2],l[NN<<2],r[NN<<2],us[NN<<2],nxt;
29     int calc(int rt,int val){
30         if(l[rt]==r[rt]) return mx[rt]>val?sum[rt]:0;
31         if(mx[rd]<=val) return calc(ld,val);
32         return (us[ld]+calc(rd,val))%p;
33     }
34     void pushup(int rt){
35         mx[rt]=max(mx[ld],mx[rd]);
36         sum[rt]=(sum[rd]+(us[ld]=calc(ld,mx[rd])))%p;
37     }
38     void build(int rt,int opl,int opr){
39         l[rt]=opl; r[rt]=opr; mx[rt]=-1;
40         if(opl==opr) return;
41         int mid=opl+opr>>1;
42         build(ld,opl,mid);
43         build(rd,mid+1,opr);
44     }
45     void insert(int rt,int pos,int i,int val){
46         if(l[rt]==r[rt]){ sum[rt]=val; mx[rt]=i; return; }
47         int mid=l[rt]+r[rt]>>1;
48         if(pos<=mid) insert(ld,pos,i,val);
49         else insert(rd,pos,i,val);
50         pushup(rt);
51     }
52     int query(int rt,int opl,int opr){
53         if(l[rt]>=opl&&r[rt]<=opr){
54             int ans=calc(rt,nxt);
55             nxt=max(nxt,mx[rt]);
56             return ans;
57         }
58         int mid=l[rt]+r[rt]>>1,ans=0;
59         if(opr>mid) (ans+=query(rd,opl,opr))%=p;
60         if(opl<=mid) (ans+=query(ld,opl,opr))%=p;
61         return ans;
62     }
63 }s;
64 signed main(){
65     n=read();
66     for(int i=1;i<=n;i++) bty[i]=read();
67     ++n; bty[n]=n; s.build(1,0,n); s.insert(1,0,0,0);
68     for(int i=1;i<=n;i++){ 
69         s.nxt=-1;
70         int tmp=s.query(1,0,bty[i]-1)%p;
71         if(!tmp) tmp=1; 
72         s.insert(1,bty[i],i,tmp);
73         if(i==n) write(tmp), putchar('\n');
74     }
75     return 0;
76 }
T3

 

posted @ 2021-07-29 17:13  keen_z  阅读(30)  评论(0编辑  收藏  举报