noip22

T1

考试的时候打的特殊性质分,然而暴力竟然写假了。

正解:

显然是个贪心,要最大化 \(a_{\min}\times b_{\min}\),肯定是要删掉若干个 \(a\) 最小,\(b\) 最小的矩形。但直接去枚举显然会T掉。

考虑如何去优化这个过程,我们可以先按 \(a\) 单关键字从小到 排序一下。 先删掉前m个 \(a\) 小的,将剩下的全压进堆里,堆按 \(b\) 从小到 排序,之后从m开始倒序枚举,将当前的矩形压到堆里,再将堆顶元素弹出,然后统计答案。

详见code。

Code
#include<queue>
#include<cstdio>
#include<algorithm>
#define MAX 100010
#define re register
#define int long long
namespace OMA
{
   int t,n,m,ans;
   bool vis[MAX];
   struct martix
   {
     int a,b;
     inline friend bool operator <(const martix &a,const martix &b)
     { return a.b>b.b; } 
   }ar[MAX];
   std::priority_queue<martix>q;
   inline bool cmp(const martix &a,const martix &b)
   { return a.a<b.a; }
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int max(int a,int b)
   { return a>b?a:b; }
   signed main()
   {
     t = read();
     while(t--)
     {
       int mina,minb;
       ans = 0,n = read(),m = read();
       for(re int i=1; i<=n; i++)
       { ar[i] = (martix){read(),read()}; }
       std::sort(ar+1,ar+1+n,cmp);
       for(re int i=m+1; i<=n; i++)
       { q.push(ar[i]); }
       mina = ar[m+1].a,minb = q.top().b;
       ans = mina*minb;
       for(re int i=m; i; i--)
       {
         q.push(ar[i]),q.pop();
         mina = ar[i].a,minb = q.top().b;
         ans = max(ans,mina*minb);
       }
       while(!q.empty())
       { q.pop(); }
       printf("%lld\n",ans);
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

如果看了的话,可能会有一个问题,如果当前元素压到堆里,删除的也是它,却还拿它来更新答案,不会错吗? 显然,如果这样的话,这个矩形肯定不是我们要留下来的,所以不会将答案更新。

T2

考试的时候同样打的特殊性质分,然而暴搜写假了,前两个点没拿分。

正解是主席树,但本人太菜,不会。所以...
image

std
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+10,inf=1e9,size=maxn*40;
int n,q,type,a[maxn],lastans,r,k,p[maxn],fa[20][maxn],dep[maxn],rt[maxn];
vector<int> g[maxn];

namespace segt{
	int cnt,sum[size],lson[size],rson[size];
	inline int newnode(int x){
		++cnt;
		sum[cnt]=sum[x];
		lson[cnt]=lson[x];rson[cnt]=rson[x];
		return cnt;
	}
	inline void push_up(int rt){
		sum[rt]=sum[lson[rt]]+sum[rson[rt]];
	}
	int insert(int rt,int l,int r,int pos){
		rt=newnode(rt);
		++sum[rt];
		if(l==r)
			return rt;
		int mid=l+r>>1;
		if(pos<=mid)
			lson[rt]=insert(lson[rt],l,mid,pos);
		else
			rson[rt]=insert(rson[rt],mid+1,r,pos);
		push_up(rt);
		return rt;
	}
	int queryl(int rt1,int rt2,int l,int r,int y){
		if(sum[rt1]==sum[rt2])
			return 0;
		if(l==r)
			return l;
		int mid=l+r>>1;
		if(y<=mid)
			return queryl(lson[rt1],lson[rt2],l,mid,y);
		else{
			int tmp=queryl(rson[rt1],rson[rt2],mid+1,r,y);
			if(tmp)
				return tmp;
			else
				return queryl(lson[rt1],lson[rt2],l,mid,mid);
		}
	}
	int queryr(int rt1,int rt2,int l,int r,int x){
		if(sum[rt1]==sum[rt2])
			return 0;
		if(l==r)
			return l;
		int mid=l+r>>1;
		if(x>mid)
			return queryr(rson[rt1],rson[rt2],mid+1,r,x);
		else{
			int tmp=queryr(lson[rt1],lson[rt2],l,mid,x);
			if(tmp)
				return tmp;
			else
				return queryr(rson[rt1],rson[rt2],mid+1,r,mid+1);
		}
	}
}
void dfs(int pos){
	for(int i=1;i<20;++i)
		fa[i][pos]=fa[i-1][fa[i-1][pos]];
	dep[pos]=dep[fa[0][pos]]+1;
	rt[pos]=segt::insert(rt[fa[0][pos]],1,inf,a[pos]);
	for(int i=0;i<g[pos].size();++i)
		if(g[pos][i]!=fa[0][pos]){
			fa[0][g[pos][i]]=pos;
			dfs(g[pos][i]);
		}
}
inline int lca(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	for(int i=19;~i;--i)
		if(dep[fa[i][u]]>=dep[v])
			u=fa[i][u];
	if(u==v)
		return u;
	for(int i=19;~i;--i)
		if(fa[i][u]!=fa[i][v])
			u=fa[i][u],v=fa[i][v];
	return fa[0][u];
}

int main(){
	freopen("e.in","r",stdin);
	freopen("e.out","w",stdout);
	scanf("%d%d%d",&n,&q,&type);
	for(int i=1;i<=n;++i)
		scanf("%d",&a[i]);
	for(int i=1,u,v;i<n;++i){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1);
	while(q--){
		scanf("%d%d",&r,&k);
		for(int i=1;i<=k;++i){
			scanf("%d",&p[i]);
			p[i]=(p[i]-1+lastans*type)%n+1;
		}
		int f=p[1],res=inf;
		for(int i=2;i<=k;++i)
			f=lca(f,p[i]);
		f=fa[0][f];
		for(int i=1,tmp;i<=k;++i){
			tmp=segt::queryl(rt[f],rt[p[i]],1,inf,r);
			if(tmp&&r-tmp<res)
				res=r-tmp;
			tmp=segt::queryr(rt[f],rt[p[i]],1,inf,r);
			if(tmp&&tmp-r<res)
				res=tmp-r;
		}
		printf("%d\n",res);
		lastans=res;
	}
	return 0;
}

所以已经好几场都有主席树了,为什么还不去学啊涉及到的都没改出来QAQ

所以我决定去按考场思路来写,先树剖,然后线段树维护。但当时脑抽,一看维护差值就没打。

其实很好解决,只要查找 \(r\) 在当前这个点到公共 \(LCA\) 这条链上的前驱后继即可,所以考虑平衡树。

一条链可以用dfn序转换为序列上的问题,所以外层套个线段树,内层套平衡树,查询的时候再按树剖的查询方式来查前驱后继即可。

思路很简单,代码很好写291行的代码,也很好调,直接冲板子即可。

如果你真的码了的话,发现T了链的那个点,很好解决,特判即可。

image

不过应该会被蒲公英图卡死,所以主席树还是要的。

好吧,我还是去学了QAQ

所以这是叫树套树套树吗

Code
#include<time.h>
#include<cstdio>
#include<stdlib.h>
#define MAX 100010
#define re register
namespace OMA
{
   int n,q,type,last,lca;
   int r,k,a[MAX],p[MAX];
   struct Graph
   {
     int next;
     int to;
   }edge[MAX<<1];
   int cnt=1,head[MAX];
   inline void add(int u,int v)
   {
     edge[++cnt].next = head[u];
     edge[cnt].to = v;
     head[u] = cnt;
   }
   int fa[MAX],son[MAX];
   int dep[MAX],size[MAX];
   int top[MAX],dfn[MAX],id[MAX];
   inline void dfs1(int u,int fat,int depth)
   {
     fa[u] = fat;
     size[u] = 1;
     dep[u] = depth;
     for(re int i=head[u]; i; i=edge[i].next)
     {
       int v = edge[i].to;
       if(v!=fat)
       {
         dfs1(v,u,depth+1);
         size[u] += size[v];
         if(!son[u]||size[v]>size[son[u]])
         { son[u] = v; }
       }
     }
   }
   inline void dfs2(int u,int t)
   { 
     top[u] = t;
     id[dfn[u] = ++cnt] = a[u];
     if(son[u])
     { dfs2(son[u],t); }
     for(re int i=head[u]; i; i=edge[i].next)
     {
       int v = edge[i].to;
       if(v!=fa[u]&&v!=son[u])
       { dfs2(v,v); }
     }
   }
   inline int LCA(int a,int b)
   {
     while(top[a]!=top[b])
     {
       if(dep[top[a]]>dep[top[b]])
       { a = fa[top[a]]; }
       else
       { b = fa[top[b]]; }
     }
     return dep[a]<dep[b]?a:b;
   }
   inline int max(int a,int b)
   { return a>b?a:b; }
   inline int min(int a,int b)
   { return a<b?a:b; }
   struct Segment_Tree
   {
     struct TREE
     { int l,r,rt; }st[MAX<<2];
     struct FHQ_Treap
     {
       int tot;
       struct TREE
       {
         int size;
         int ls,rs;
         int key,val;
       }bst[MAX*20];
       inline void Push_up(int p)
       { bst[p].size = bst[bst[p].ls].size+bst[bst[p].rs].size+1; }
       inline int new_pot(int val)
       {
         bst[++tot].val = val;
         bst[tot].size = 1;
         bst[tot].key = rand();
         return tot;
       }
       inline void split(int p,int val,int &p1,int &p2)
       {
         if(!p)
         { p1 = p2 = 0; return ; }
         if(bst[p].val<=val)
         { split(bst[p1 = p].rs,val,bst[p].rs,p2); }
         else
         { split(bst[p2 = p].ls,val,p1,bst[p].ls); }
         Push_up(p);
       }
       inline int merge(int p1,int p2)
       {
         if(!p1||!p2)
         { return p1|p2; }
         if(bst[p1].key<bst[p2].key)
         {
           bst[p1].rs = merge(bst[p1].rs,p2);
           Push_up(p1);
           return p1;
         }
         else
         {
           bst[p2].ls = merge(p1,bst[p2].ls);
           Push_up(p2);
           return p2;
         }
       }
       inline void insert(int &root,int val)
       {
         int p1 = 0,p2 = 0;
         split(root,val,p1,p2);
         root = merge(merge(p1,new_pot(val)),p2);
       }
       inline int pre(int &root,int val)
       {
         int p1 = 0,p2 = 0;
         split(root,val,p1,p2);
         if(!p1)
         { return -0x7f7f7f7f; }
         int p = p1;
         while(bst[p].rs)
         { p = bst[p].rs; }
         root = merge(p1,p2);
         return bst[p].val;
       }
       inline int suf(int &root,int val)
       {
         int p1 = 0,p2 = 0;
         split(root,val-1,p1,p2);
         int p = p2;
         if(!p2)
         { return 0x7f7f7f7f; }
         while(bst[p].ls)
         { p = bst[p].ls; }
         root = merge(p1,p2);
         return bst[p].val;
       }
     }Treap;
     inline int ls(int p)
     { return p<<1; }
     inline int rs(int p)
     { return p<<1|1; }
     inline void build(int p,int l,int r)
     {
       st[p].l = l,st[p].r = r;
       if(l==r)
       { st[p].rt = Treap.new_pot(id[l]); return ; }
       for(re int i=l; i<=r; i++)
       { Treap.insert(st[p].rt,id[i]); }
       int mid = (l+r)>>1;
       build(ls(p),l,mid),build(rs(p),mid+1,r);
     }
     inline int Pre(int p,int l,int r,int val)
     {
       if(l<=st[p].l&&st[p].r<=r)
       { return Treap.pre(st[p].rt,val); }
       int pre = -0x7f7f7f7f,mid = (st[p].l+st[p].r)>>1;
       if(l<=mid)
       { pre = max(pre,Pre(ls(p),l,r,val)); }
       if(r>mid)
       { pre = max(pre,Pre(rs(p),l,r,val)); }
       return pre;
     }
     inline int Suf(int p,int l,int r,int val)
     {
        if(l<=st[p].l&&st[p].r<=r)
        { return Treap.suf(st[p].rt,val); }
        int suf = 0x7f7f7f7f,mid = (st[p].l+st[p].r)>>1;
        if(l<=mid)
        { suf = min(suf,Suf(ls(p),l,r,val)); }
        if(r>mid)
        { suf = min(suf,Suf(rs(p),l,r,val)); }
        return suf;
     }
     inline void swap(int &a,int &b)
     { int t=a; a=b; b=t; }
     inline int PRE(int a,int b)
     {
       int pre = -0x7f7f7f7f;
       while(top[a]!=top[b])
       {
         if(dep[top[a]]<dep[top[b]])
         { swap(a,b); }
         pre = max(pre,Pre(1,dfn[top[a]],dfn[a],r));
         a = fa[top[a]];
       }
       if(dep[a]>dep[b])
       { swap(a,b); }
       pre = max(pre,Pre(1,dfn[a],dfn[b],r));
       return pre;
     }
     inline int SUF(int a,int b)
     {
       int suf = 0x7f7f7f7f;
       while(top[a]!=top[b])
       {
         if(dep[top[a]]<dep[top[b]])
         { swap(a,b); }
         suf = min(suf,Suf(1,dfn[top[a]],dfn[a],r));
         a = fa[top[a]];
       }
       if(dep[a]>dep[b])
       { swap(a,b); }
       suf = min(suf,Suf(1,dfn[a],dfn[b],r));
       return suf;
     }
   }Tree;
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int abs(int a)
   { return a>=0?a:-a; }
   signed main()
   {
     //freopen("node.in","r",stdin);
     //freopen("my.out","w",stdout);
     srand(time(NULL));
     n = read(),q = read(),type = read();
     for(re int i=1; i<=n; i++)
     { a[i] = read(); }
     bool flag = true;
     for(re int i=1,u,v; i<=n-1; i++)
     {
       u = read(),v = read();
       add(u,v),add(v,u);
       if(v!=u+1)
       { flag = false; }
     }
     if(flag)
     {
       for(re int i=1; i<=q; i++)
       {
         int ans = 0x7f7f7f7f;
         int L = 0x3f3f3f3f,R = 0;
         r = read(),k = read();
         for(re int j=1; j<=k; j++)
         { p[j] = (read()-1+last*type)%n+1; L = min(L,p[j]),R = max(R,p[j]); }
         for(re int j=L; j<=R; j++)
         { ans = min(ans,abs(a[j]-r)); if(!ans){ break ; }}
         printf("%d\n",ans);
       }
       return 0;
     }
     dfs1(1,0,0),cnt = 0,dfs2(1,1);
     Tree.build(1,1,n);
     for(re int i=1; i<=q; i++)
     {
       int ans = 0x7f7f7f7f;
       r = read(),k = read();
       for(re int j=1; j<=k; j++)
       { p[j] = (read()-1+last*type)%n+1; }
       lca = p[1];
       for(re int j=2; j<=k; j++)
       { lca = LCA(lca,p[j]); }
       //printf("LCA=%d\n",lca);
       for(re int j=1; j<=k; j++)
       {
         int pre = Tree.PRE(p[j],lca);
         int suf = Tree.SUF(p[j],lca);
         //printf("pre=%d suf=%d\n",pre,suf);
         if(!pre)
         { pre = 0x7f7f7f7f; }
         if(!suf)
         { suf = 0x7f7f7f7f; }
         ans = min(ans,min(abs(pre-r),abs(suf-r)));
         if(!ans)
         { break ; }
       }
       last = ans;
       printf("%d\n",ans);
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T3

为什么我直接冲暴力都只能拿特判分啊

果然还是太菜了

正解:

还在改,先咕了话说,场场咕t3真的好吗QAQ

所以....

image

posted @ 2021-07-22 11:07  -OMA-  阅读(87)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end