2021.7.21考试总结[NOIP模拟22]

终于碾压小熠了乐死了

T1 d


小贪心一波直接出正解,没啥好说的(bushi

好像可以主席树暴力找,但我怎么可能会呢?好像可以堆优化简单找,但我怎么可能想得到呢?

那怎么办?昨天两道单调指针加桶,我直接使用经典方法。

先把a该删的全删了,之后按a填一个按b删一个,O(m)枚举所有情况。

code:

 1 #include<bits/stdc++.h>
 2 #define debug exit(0)
 3 #define LL long long
 4 using namespace std;
 5 const int NN=1e5+5;
 6 int n,T,m,ta[NN],tb[NN],tma,tmb,tmp;
 7 struct jz{
 8     int a,b,id;
 9 }s[NN],sa[NN],sb[NN];
10 LL ans;
11 bool flag=0,vis[NN];
12 inline int Min(int a,int b){ return a<b?a:b; }
13 inline LL Max(LL a,LL b){ return a<b?b:a; }
14 inline bool cmp1(jz x,jz y){ return x.a==y.a?(x.b<y.b):(x.a<y.a); }
15 inline bool cmp2(jz x,jz y){ return x.b==y.b?(x.a<y.a):(x.b<y.b); }
16 inline int read(){
17     int x=0,f=1;
18     char ch=getchar();
19     while(ch<'0'||ch>'9'){
20         if(ch=='-') f=-1;
21         ch=getchar();
22     }
23     while(ch>='0'&&ch<='9'){
24         x=(x<<1)+(x<<3)+(ch^48);
25         ch=getchar();
26     }
27     return x*f;
28 }
29 void write(LL x){
30     if(x<0) putchar('-'), x=-x;
31     if(x>9) write(x/10);
32     putchar(x%10+'0');
33 }
34 void clear(){
35     ans=0; tma=tmb=INT_MAX; tmp=1;
36     memset(vis,0,sizeof(vis));
37     memset(ta,0,sizeof(ta));
38     memset(tb,0,sizeof(tb));
39 }
40 void solve(){
41     while(!ta[tma]) ++tma;
42     while(!tb[tmb]) ++tmb;
43     ans=max(ans,1ll*tma*tmb);
44 }
45 int main(){
46     freopen("d2.in","r",stdin);
47     freopen("out","w",stdout);
48     T=read();
49     while(T--){
50         clear();
51         n=read(); m=read();
52         for(int i=1;i<=n;i++) s[i].a=read(), s[i].b=read(), s[i].id=i;
53         for(int i=1;i<=n;i++){
54             sa[i]=s[i]; sb[i]=s[i];
55             ++ta[s[i].a]; ++tb[s[i].b];
56             tma=Min(tma,s[i].a); tmb=Min(tmb,s[i].b);
57         }
58         sort(sa+1,sa+n+1,cmp1); sort(sb+1,sb+n+1,cmp2);
59         for(int i=1;i<=m;i++){
60             vis[sa[i].id]=1;
61             --ta[sa[i].a]; --tb[sa[i].b];
62         }
63         solve();
64         for(int i=1;i<=m;i++){
65             if(sa[m-i+1].b<=tmb) continue;
66             vis[sa[m-i+1].id]=0; ++ta[sa[m-i+1].a]; ++tb[sa[m-i+1].b];
67             if(sa[m-i+1].a<tma) tma=sa[m-i+1].a;
68             while(vis[sb[tmp].id]) tmp++;
69             vis[sb[tmp].id]=1; --ta[sb[tmp].a]; --tb[sb[tmp].b];
70             solve();
71         }
72         write(ans); putchar('\n');
73     }
74     return 0;
75 }
T1


T2 e


没想到吧又是道主席树
首先认识到联通块由所有点的LCA与点的简单路径构成。那么我们就应该写一种数据结构,支持查找链上的前驱后继,主席树。

不会怎么办?问JYFHYX。树链剖分套线段树套平衡树加XIN_TEAM优化直接A过。

  1 #include<bits/stdc++.h>
  2 #define inf 2e9
  3 #define lid id<<1
  4 #define rid id<<1|1
  5 using namespace std;
  6 inline int read()
  7 {
  8     int x=0,f=1;
  9     char ch=getchar();
 10     while(ch<'0'||ch>'9')
 11     {
 12         if(ch=='-') f=-1;
 13         ch=getchar();
 14     }
 15     while(ch>='0'&&ch<='9')
 16     {
 17         x=(x<<1)+(x<<3)+(ch^48);
 18         ch=getchar();
 19     }
 20     return x*f;
 21 }
 22 const int maxn=2e6+1;
 23 struct treap{
 24     int l,r,size,cnt,dat,val;
 25 }a[maxn];
 26 struct seg_tree{
 27     int l,r,root,lazy;
 28 }tr[maxn<<2];
 29 int n,q,type,tot;
 30 struct node{
 31     int to,nxt;
 32 }e[maxn*2];
 33 int head[maxn];
 34 bool flag=1;
 35 int val[maxn];
 36 bool vis[100001];
 37 int w[maxn],num;
 38 int dfn[maxn],size[maxn],son[maxn],fa[maxn],top[maxn];
 39 int dep[maxn],cnt;
 40 int cz[maxn],rr,k;
 41 inline void add(int x,int y)
 42 {
 43     e[++num].to=y;
 44     e[num].nxt=head[x];
 45     head[x]=num;
 46     if(x!=y+1&&y!=x+1) flag=0;
 47     swap(x,y);
 48     e[++num].to=y;
 49     e[num].nxt=head[x];
 50     head[x]=num;
 51 }
 52 inline int New(int val)
 53 {
 54     a[++tot].val=val;
 55     a[tot].dat=rand();
 56     a[tot].cnt=a[tot].size=1;
 57     return tot;
 58 }
 59 inline void pushup(int p)
 60 {
 61     a[p].size=a[a[p].l].size+a[a[p].r].size+1;
 62 }
 63 inline int merge(int x,int y)
 64 {
 65     if(!x||!y)
 66     return x|y;
 67     if(a[x].dat<a[y].dat)
 68     {
 69         a[x].r=merge(a[x].r,y);
 70         pushup(x);
 71         return x;
 72     }
 73     else
 74     {
 75         a[y].l=merge(x,a[y].l);
 76         pushup(y);
 77         return y;
 78     }
 79 }
 80 inline void split(int now,int kk,int &x,int &y)
 81 {
 82     if(!now)
 83     {
 84         x=y=0;
 85         return ;
 86     }
 87     if(kk>=a[now].val)
 88     {
 89         x=now;
 90         split(a[now].r,kk,a[now].r,y);
 91     }
 92     else
 93     {
 94         y=now;
 95         split(a[now].l,kk,x,a[now].l);
 96     }
 97     pushup(now);
 98 }
 99 inline void insert(int &root,int val)
100 {
101     int x,y;
102     split(root,val,x,y);
103     root=merge(merge(x,New(val)),y);    
104 }
105 void build(int id,int l,int r)
106 {
107     tr[id].l=l; tr[id].r=r;
108     if(l==r)
109     {
110         tr[id].root=New(w[l]);
111         return ;
112     }
113     for(int j=l;j<=r;j++)
114     insert(tr[id].root,w[j]);
115     int mid=(l+r)>>1;
116     build(lid,l,mid);
117     build(rid,mid+1,r);
118 }
119 inline int pre(int &root,int val)
120 {
121     int x,y,ans;
122     split(root,val-1,x,y);
123     if(!x) return -inf;
124     int kk=x;
125     while(a[kk].r)
126     kk=a[kk].r;
127     ans=a[kk].val;
128     root=merge(x,y);
129     return ans;
130 }
131 inline int nxt(int &root,int val)
132 {
133     int x,y,ans;
134     split(root,val,x,y);
135     if(!y) return inf;
136     int kk=y;
137     while(a[kk].l)
138     kk=a[kk].l;
139     ans=a[kk].val;
140     root=merge(x,y);
141     return ans;
142 }
143 inline int askpre(int id,int l,int r,int d)
144 {
145     if(tr[id].l>=l&&tr[id].r<=r)
146     return pre(tr[id].root,d);
147     int mid=(tr[id].l+tr[id].r)>>1;
148     int ans=-inf;
149     if(l<=mid)
150     ans=max(ans,askpre(lid,l,r,d));
151     if(r>mid)
152     ans=max(ans,askpre(rid,l,r,d));
153     return ans;
154 }
155 inline int asknxt(int id,int l,int r,int d)
156 {
157     if(tr[id].l>=l&&tr[id].r<=r)
158     return nxt(tr[id].root,d);
159     int mid=(tr[id].l+tr[id].r)>>1;
160     int ans=inf;
161     if(l<=mid)
162     ans=min(ans,asknxt(lid,l,r,d));
163     if(r>mid)
164     ans=min(ans,asknxt(rid,l,r,d));
165     return ans;
166 }
167 void dfs1(int x,int f)
168 {
169     size[x]=1;
170     for(int i=head[x];i;i=e[i].nxt)
171     {
172         int y=e[i].to;
173         if(y==f) continue;
174         dep[y]=dep[x]+1;
175         fa[y]=x;
176         dfs1(y,x);
177         size[x]+=size[y];
178         if(size[son[x]]<size[y]) 
179         son[x]=y;
180     }
181 }
182 void dfs2(int x,int f)
183 {
184     top[x]=f;
185     dfn[x]=++cnt;
186     w[cnt]=val[x];
187     if(!son[x]) return ;
188     dfs2(son[x],f);
189     for(int i=head[x];i;i=e[i].nxt)
190     {
191         int y=e[i].to;
192         if(y!=fa[x]&&y!=son[x])
193         dfs2(y,y);
194     }
195 }
196 inline int treepre(int x,int y,int jb)
197 {
198     int ans=-inf;
199     while(top[x]!=top[y])
200     {
201         if(dep[top[x]]<dep[top[y]])
202         swap(x,y);
203         ans=max(ans,askpre(1,dfn[top[x]],dfn[x],jb));
204         x=fa[top[x]];
205     }
206     if(dep[x]>dep[y])
207     swap(x,y);
208     ans=max(ans,askpre(1,dfn[x],dfn[y],jb));
209     return ans;
210 }
211 inline int treenxt(int x,int y,int jb)
212 {
213     int ans=inf;
214     while(top[x]!=top[y])
215     {
216         if(dep[top[x]]<dep[top[y]])
217         swap(x,y);
218         ans=min(ans,asknxt(1,dfn[top[x]],dfn[x],jb));
219         x=fa[top[x]];
220     }
221     if(dep[x]>dep[y])
222     swap(x,y);
223     ans=min(ans,asknxt(1,dfn[x],dfn[y],jb));
224     return ans;
225 }
226 inline int LCA(int x, int y) 
227 {
228         while(top[x]!=top[y]) 
229         {
230              if(dep[top[x]]<dep[top[y]]) 
231             swap(x,y);
232             x=fa[top[x]];
233         }
234         return dep[x]<dep[y]?x:y;
235 }
236 inline void dfs3(int x,int goal,int &sum)
237 {
238     if(!x) return ;
239     if(vis[x])  return ;
240     vis[x]=1;
241     sum=min(sum,abs(val[x]-rr));
242     if(x==goal) return ;
243     dfs3(fa[x],goal,sum);
244 }
245 signed main()
246 {
247     //freopen("e7.in","r",stdin);
248     //freopen("out","w",stdout);
249     srand(time(0));
250     n=read(),q=read(),type=read();
251     for(int i=1;i<=n;i++) val[i]=read();
252     for(int i=1;i<n;i++) add(read(),read());
253     dfs1(1,0);
254     dfs2(1,1);
255     if(flag==1)
256     {
257         for(int i=1;i<=q;i++)
258         {
259             memset(vis,0,sizeof(vis));
260             rr=read(),k=read();
261             for(int j=1;j<=k;j++) cz[j]=read();
262             int ans=inf;
263             int lca=cz[1];
264             for(int j=2;j<=k;j++) 
265             lca=LCA(lca,cz[j]);
266             for(int j=1;j<=k;j++)
267             dfs3(cz[j],lca,ans);
268             printf("%d\n",ans);
269         }
270         return 0;
271     }
272     else
273     {
274         build(1,1,n);
275         int ans=0;
276         for(int i=1;i<=q;i++)
277         {
278             rr=read(),k=read();
279             for(int j=1;j<=k;j++) cz[j]=((read()-1+type*ans)%n)+1;
280             ans=inf;
281             int lca=cz[1];
282             for(int j=2;j<=k;j++) 
283             lca=LCA(lca,cz[j]);
284             for(int j=1,tmp;j<=k;j++)
285             {
286                 tmp=treepre(lca,cz[j],rr+1);
287                 if(ans>abs(tmp-rr)) ans=abs(tmp-rr);
288                 tmp=treenxt(lca,cz[j],rr-1);
289                 if(ans>abs(tmp-rr)) ans=abs(tmp-rr);
290             }
291             printf("%d\n",ans);
292         }
293     }
294 }
T2JYFHYX的代码

但一般人显然没有那种毅力。学zxs吧。

从根开始DFS,途中插入每个值,继承父亲的信息,之后查找链上r的前驱和后继更新答案。

查前驱先查右儿子,如果有直接返回,不然就查左儿子,后继同理。具体看代码。

code:

  1 #include<bits/stdc++.h>
  2 #define debug exit(0)
  3 using namespace std;
  4 const int NN=1e5+5,inf=2e9;
  5 int n,q,R[NN<<2],k,type,a[NN],to[NN<<1],nex[NN<<1],head[NN],num,last,has[NN<<3],ext,h;
  6 int dep[NN],siz[NN],son[NN],fa[NN],top[NN],dfn[NN],id[NN],cnt;
  7 vector<int>ask[NN<<2];
  8 struct zxs_tree{
  9     int sum[NN*80],root[NN*80],tot,lc[NN*80],rc[NN*80];
 10     void pushup(int rt){
 11         sum[rt]=sum[lc[rt]]+sum[rc[rt]];
 12     }
 13     void insert(int x,int &rt,int fom,int l,int r){
 14         rt=++tot;
 15         sum[rt]=sum[fom]+1; lc[rt]=lc[fom]; rc[rt]=rc[fom];
 16         if(l==r) return;
 17         int mid=l+r>>1;
 18         if(x<=mid) insert(x,lc[rt],lc[fom],l,mid);
 19         else insert(x,rc[rt],rc[fom],mid+1,r);
 20         pushup(rt);
 21     }
 22     int queryl(int rt1,int rt2,int l,int r,int x){
 23         if(sum[rt1]==sum[rt2]) return -1;
 24         if(l==r) return l;
 25         int mid=l+r>>1;
 26         if(x<=mid) return queryl(lc[rt1],lc[rt2],l,mid,x);
 27         int tmp=queryl(rc[rt1],rc[rt2],mid+1,r,x);
 28         return tmp==-1?queryl(lc[rt1],lc[rt2],l,mid,x):tmp;
 29     }
 30     int queryr(int rt1,int rt2,int l,int r,int x){
 31         if(sum[rt1]==sum[rt2]) return -1;
 32         if(l==r) return l;
 33         int mid=l+r>>1;
 34         if(x>mid) return queryr(rc[rt1],rc[rt2],mid+1,r,x);
 35         int tmp=queryr(lc[rt1],lc[rt2],l,mid,x);
 36         return tmp==-1?queryr(rc[rt1],rc[rt2],mid+1,r,x):tmp;
 37     }
 38 }s;
 39 inline int read(){
 40     int x=0,f=1;
 41     char ch=getchar();
 42     while(ch<'0'||ch>'9'){
 43         if(ch=='-') f=-1;
 44         ch=getchar();
 45     }
 46     while(ch>='0'&&ch<='9'){
 47         x=(x<<1)+(x<<3)+(ch^48);
 48         ch=getchar();
 49     }
 50     return x*f;
 51 }
 52 void write(int x){
 53     if(x<0) putchar('-'), x=-x;
 54     if(x>9) write(x/10);
 55     putchar(x%10+'0');
 56 }
 57 inline void add(int a,int b){
 58     to[++num]=b; nex[num]=head[a]; head[a]=num;
 59     to[++num]=a; nex[num]=head[b]; head[b]=num;
 60 }
 61 void dfs1(int f,int s){
 62     fa[s]=f; dep[s]=dep[f]+1; siz[s]=1;
 63     for(int i=head[s];i;i=nex[i]){
 64         int v=to[i];
 65         if(v==f) continue;
 66         dfs1(s,v);
 67         siz[s]+=siz[v];
 68         if(siz[v]>siz[son[s]]) son[s]=v;
 69     }
 70 }
 71 void dfs2(int t,int s){
 72     dfn[s]=++cnt; id[cnt]=s; top[s]=t;
 73     if(!son[s]) return;
 74     dfs2(t,son[s]);
 75     for(int i=head[s];i;i=nex[i]){
 76         int v=to[i];
 77         if(v!=fa[s]&&v!=son[s]) dfs2(v,v);
 78     }
 79 }
 80 void dfs3(int st){
 81     s.insert(a[st],s.root[st],s.root[fa[st]],1,ext);
 82     for(int i=head[st];i;i=nex[i]){
 83         int v=to[i];
 84         if(v==fa[st]) continue;
 85         dfs3(v);
 86     }
 87 }
 88 inline int LCA(int x,int y){
 89     int fx=top[x],fy=top[y];
 90     while(fx!=fy)
 91         if(dep[fx]<dep[fy]) y=fa[fy], fy=top[y];
 92         else x=fa[fx], fx=top[x];
 93     return dep[x]<dep[y]?x:y;
 94 }
 95 void init(){
 96     sort(has+1,has+h+1);
 97     ext=unique(has+1,has+h+1)-has-1;
 98     for(int i=1;i<=n;i++)
 99         a[i]=lower_bound(has+1,has+ext+1,a[i])-has;
100     for(int i=1;i<=q;i++)
101         R[i]=lower_bound(has+1,has+ext+1,R[i])-has;
102 }
103 int main(){
104     n=read(); q=read(); type=read();
105     for(int i=1;i<=n;i++) has[++h]=a[i]=read();
106     for(int i=1;i<n;i++) add(read(),read());
107     for(int i=1;i<=q;i++){
108         R[i]=has[++h]=read(); k=read();
109         for(int j=1;j<=k;j++) ask[i].push_back(read());
110     }
111     init(); dfs1(0,1); dfs2(1,1); dfs3(1);
112     for(int i=1;i<=q;i++){
113         for(int j=0;j<ask[i].size();j++)
114             ask[i][j]=(ask[i][j]-1+last*type)%n+1;
115         int lca=ask[i][0],ans=INT_MAX;
116         for(int j=1;j<ask[i].size();j++) lca=LCA(lca,ask[i][j]);
117         for(int j=0;j<ask[i].size();j++){
118             int pre=s.queryl(s.root[ask[i][j]],s.root[fa[lca]],1,ext,R[i]);
119             int nex=s.queryr(s.root[ask[i][j]],s.root[fa[lca]],1,ext,R[i]);
120             cout<<(pre==-1?-1:has[pre])<<' '<<(nex==-1?-1:has[nex])<<endl;
121             if(pre!=-1) ans=min(ans,has[R[i]]-has[pre]);
122             if(nex!=-1) ans=min(ans,has[nex]-has[R[i]]);
123         } last=ans;
124 //        write(ans);
125         putchar('\n');
126     } 
127     return 0;
128 }
T2zxs的zxs做法

T3 f


可恶。还没改出来。

posted @ 2021-07-22 11:51  keen_z  阅读(32)  评论(0编辑  收藏  举报