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\) 个演讲在两个报告厅中举行,第一个报告厅中的开始时间是 \(sa_i\) ,结束时间是 \(ea_i\) ,问有没有演讲的子集 \(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\) 序,求出每个点的 \(id\)\(size\) ,然后问题就变成了一个区间问题,可以发现颜色数 \(\leq60\) ,正好差不多卡在 long long,所以我们往二进制方向想,我们可以状压每个颜色,可以用 \(bitset\) 来维护,然后建一颗线段树,只不过更新变成了或运算,区间即为 \([id_x,id_x+size_x-1]\) ,结果就是二进制位上一的个数。

#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 @ 2024-01-30 15:26  noipwen  阅读(42)  评论(0)    收藏  举报