cd DS

Ice-cream Tycoo(SGU 311)

题目大意

商店里初始时没有物品,支持以下两种操作

  • 增加 n 个价格 c 的物品
  • 对于一名想用 t 元钱购买前 n 便宜的物品的顾客,若这些物品总价不超过 t 则从商店中移除,否则不做操作,报告是否进行了操作

思路

我们可以以价格为端点植一颗线段树,存储有多少个是这个价格的物品,对于第一个我们直接在 c 上加上 n
对于第二种我们先把不可以的解决了:能发现是如果总数小于 n 或者是 y 小于最小的为不可以,否则就找到最便宜的然后删去即可(具体步骤为先找到最小的下标不为 0 的点,然后将它减去,重复此操作)。

#include<bits/stdc++.h>
#define ll long long
#define mm 1000010
#define int long long
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
int p[mm*3],sum[mm*3];
ll a[mm];
void push(int x)
{
p[x]=p[x<<1]+p[x<<1|1];
sum[x]=sum[x<<1]+sum[x<<1|1];
}
void updata(int l,int r,int pd,int u,int x)
{
if(l==r)
{
p[x]+=u;
sum[x]+=1LL*u*l;
return ;
}
int mid=(l+r)>>1;
if(pd<=mid) updata(l,mid,pd,u,x<<1);
else updata(mid+1,r,pd,u,x<<1|1);
push(x);
}
ll ask_sum(int l,int r,int u,int x)
{
if(l==r) return 1LL*l*u;
int mid=(l+r)>>1;
if(u<=p[x<<1]) return (ll)ask_sum(l,mid,u,x<<1);
else return (ll)sum[x<<1]+ask_sum(mid+1,r,u-p[x<<1],x<<1|1);
}
int ask_id(int l,int r,int x)
{
if(l==r) return l;
int mid=(l+r)>>1;
if(p[x<<1]) return ask_id(l,mid,x<<1);
else return ask_id(mid+1,r,x<<1|1);
}
void ARRIVE(int x,int y)
{
a[y]+=x;
updata(1,1000000,y,x,1);
}
void BUY(int n,int y)
{
if(n>p[1])
{
puts("UNHAPPY");
return ;
}
if((ll)ask_sum(1,1000000,n,1)>y)
{
puts("UNHAPPY");
return ;
}
puts("HAPPY");
while(n)
{
int id=ask_id(1,1000000,1);
int x=min(n*1LL,a[id]);
updata(1,1000000,id,-x,1);
a[id]-=x,n-=x;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
string s;
while(cin>>s)
{
int x,y;
cin>>x>>y;
if(s[0]=='A')
ARRIVE(x,y);
else
BUY(x,y);
}
return 0;
}

New Year and Conference(CF1284D)

题目大意

n 个演讲,第 i 个演讲在两个报告厅中举行,第一个报告厅中的开始时间是 sai ,结束时间是 eai ,问有没有演讲的子集 S ,使得所有 S 中的演讲都是在一个报告厅中不存在重叠,在另一个中重叠?

思路

可以发现如果不存在任何一对讲座在一个场地中冲突,另一场地不冲突,那么就不会存在一个子集的讲座不合法,反之则一定存在不合法的子集。所以我们只需求正确性即可,哈希即可。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mm 100010
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
struct node{
int u,id,k;
node() {}
node(int u, int id, int k):u(u),id(id),k(k){}
friend bool operator <(node a,node b)
{
if(a.u==b.u)
return a.k<b.k;
return a.u<b.u;
}
}a1[mm],a2[mm];
ull v[mm],s[mm];
int n;
int main()
{
n=read();
srand(time(0));
for(int i=1;i<=n;i++)
{
v[i]=(ull)rand()<<31|rand();
a1[i*2-1]=node(read(),i,0);
a1[i<<1]=node(read(),i,1);
a2[i*2-1]=node(read(),i,0);
a2[i<<1]=node(read(),i,1);
}
n*=2;
sort(a1+1,a1+n+1);
sort(a2+1,a2+n+1);
ull x=0;
for(int i=1;i<=n;i++)
if(a1[i].k) x^=v[a1[i].id];
else s[a1[i].id]^=x;
x=0;
for(int i=n;i>=1;i--)
if(!a1[i].k) x^=v[a1[i].id];
else s[a1[i].id]^=x;
x=0;
for(int i=1;i<=n;i++)
if(a2[i].k) x^=v[a2[i].id];
else s[a2[i].id]^=x;
x=0;
for(int i=n;i>=1;i--)
if(!a2[i].k) x^=v[a2[i].id];
else s[a2[i].id]^=x;
int flag=0;
for(int i=1;i<=n/2;i++)
flag|=s[i]>0;
if(flag==0)
puts("YES");
else
puts("NO");
return 0;
}

New Year Tree(CF620E)

题目大意

给一棵树,现在每个节点上有一个颜色(<=60),有一些查询:

  • 把一个子树中所有的节点都赋成同样的颜色
  • 求出一个子树中出现过的颜色个数

思路

我们如果直接在树上进行操作显然非常麻烦,所以我们先求出这棵树的 dfs 序,求出每个点的 idsize ,然后问题就变成了一个区间问题,可以发现颜色数 60 ,正好差不多卡在 long long,所以我们往二进制方向想,我们可以状压每个颜色,可以用 bitset 来维护,然后建一颗线段树,只不过更新变成了或运算,区间即为 [idx,idx+sizex1] ,结果就是二进制位上一的个数。

#include<bits/stdc++.h>
#define ll long long
#define mm 400010
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
vector<int> e[mm];
bitset<64> tree[mm<<2];
int n,m;
int id[mm],idx[mm],cnt;
int siz[mm];
int a[mm],lazy[mm<<2];
void dfs1(int x,int f)
{
siz[x]=1;
id[x]=++cnt,idx[cnt]=x;
for(auto u:e[x])
{
if(u==f)
continue;
dfs1(u,x);
siz[x]+=siz[u];
}
}
void push(int x){tree[x]=tree[x<<1]|tree[x<<1|1];}
void mark(int x,int k)
{
lazy[x]=k;
tree[x].reset();
tree[x].set(k);
}
void pushdown(int l,int r,int x)
{
if(!lazy[x])
return ;
mark(x<<1,lazy[x]);
mark(x<<1|1,lazy[x]);
lazy[x]=0;
}
void build(int l,int r,int x)
{
if(l==r)
{
tree[x].set(a[idx[l]]);
return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
push(x);
}
void update(int pos,int l,int r,int x,int y,int k)
{
if(x<=l && r<=y)
{
mark(pos,k);
return;
}
int mid=(l+r)>>1;
pushdown(l,r,pos);
if(x<=mid) update(pos<<1,l,mid,x,y,k);
if(y>mid) update(pos<<1|1,mid+1,r,x,y,k);
push(pos);
}
bitset<64> ask(int pos,int l,int r,int x,int y)
{
if(x<=l && r<=y)
return tree[pos];
pushdown(l,r,pos);
int mid=(l+r)>>1;
bitset<64> bb;
if(x<=mid) bb|=ask(pos<<1,l,mid,x,y);
if(y>mid) bb|=ask(pos<<1|1,mid+1,r,x,y);
return bb;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(1,0);
build(1,n,1);
while(m--)
{
int op=read();
if(op==1)
{
int x=read(),y=read();
update(1,1,n,id[x],id[x]+siz[x]-1,y);
}
else
{
int x=read();
printf("%d\n",ask(1,1,n,id[x],id[x]+siz[x]-1).count());
}
}
return 0;
}

小总

感觉下午讲的前两题和后两题还不难,中间忽然出现一个神秘题,题目大部分是CF上的,平均3000+

posted @   noipwen  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示