开始补题 好多题目都不会呀 (comet oj 8 d 补题记 很有技巧)

菜菜太菜,但他不想种菜。

有 nn 块土地,每块土地有一个菜值。它们之间有 mm 条小路,每条连接两块土地,小路只能单向通行,不存在一条小路两端连接同一块土地,但可能存在两条小路两端连接的土地分别相同。如果存在一条从土地 uu 到土地 vv 的小路,则称 uu 能直接到达 vv。

菜菜可以购买一些土地,他必须在其中选择一块建造自己的家,所购买的剩下的土地都被作为菜地。因为菜菜不想种菜,所以他希望从他家能直接到达的土地中,一块菜地也没有(如果菜菜家不能直接到达任何一块土地,这也能满足他的愿望)。

菜菜提出了 qq 个问题,每个问题给出 L,RL,R ,询问如果他购买了第 LL 到第 RR 块之间的所有土地,那么所有满足他愿望的建造家的选址的菜值之和是多少?

对于这个问题 我们可以发现其实这个菜地是有自己的管辖范围的 他管辖的范围就是离他最近的l[i] 和 r[i] 只要所询问的区间在我这个范围只能那么我就可以加上这个菜地的值 ,对于m条小路的处理就是我们可以先预处理出l[i] and r[i] 预处理出这个之后 考虑对于询问进行离线处理 按照询问的右端点进行排序 然后一个一个处理询问 还要就是对于菜地值的和 利用树状数组进行维护菜地值的和

利用判断区间的右端点有没有超过当前的第i个的管辖范围来觉得是否消除第i个的影响 通过l是不是在 L 到 i 之间判断是否加入这个菜地的菜地值 通过一个vector<seg_> 来保存区间的影响是否 其中seg保存的是我当前第i个管辖的范围 在r[i] 这个点加入一个消除管辖范围的影响的seg_节点
具体看代码 询问离线加区间递增步步处理 还有消除影响 要好好记一下这个技巧

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define se second
#define fi first
#define pii pair<int,int>
#define lowbit(x) x&(-x)
typedef long long ll;
int lson(int p) {return p * 2;}
int rson(int p) {return p * 2 + 1;}
const int mod = 1e9 + 7;

const int maxn = 1e6 + 10;
const long long int inf = 1e17 + 10;
int n,m,q;
struct que_{
    int l,r;
    int id;
}a[maxn];

struct seq_{
    int l,r;
    ll w;
};

vector<seq_> v[maxn];

int l[maxn],r[maxn];
ll val[maxn],c[maxn];

ll t_ans[maxn];
ll ask(int x)
{
    ll ans = 0;
    for(;x; x -= lowbit(x)) ans += c[x];
    return ans;
}
void add(int x,int y)
{
    for(;x <= n; x += lowbit(x)) c[x] += y;
}
bool cmp(que_ x,que_ y)
{
    return x.r < y.r;
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(int i = 1; i <= n; i++)
    {
        l[i] = 0,r[i] = n + 1;
        scanf("%lld",&val[i]);
    }
    for(int i = 1; i <= m; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x > y) l[x] = max(l[x],y); // 检测范围
        else r[x] = min(r[x],y);
    }
    for(int i = 1; i <= q; i++)
    {
        a[i].id = i;
        scanf("%d%d",&a[i].l,&a[i].r);
    }
    sort(a + 1,a + q + 1,cmp);
    for(int i = 1; i <= n; i++)
    {
        v[i].pb(seq_{l[i] + 1,i,val[i]}); // 增加我这个点i的影响
        v[r[i]].pb(seq_{l[i] + 1,i,-val[i]}); // 当前询问超过我的r了 那么就将我这个影响消除掉
    }
    int l_ = 1;
    for(int i = 1; i <= q; i++)
    {
        while(l_ <= a[i].r)
        {
            for(int j = 0; j < v[l_].size(); j++) // 消除前面的影响 增加自己当前的影响
            {
                add(v[l_][j].l,v[l_][j].w); 
                add(v[l_][j].r + 1,-v[l_][j].w);
            }
            l_++;
        }
        t_ans[a[i].id] = ask(a[i].l); // 询问一下菜地之和
    }
    ll ans  = 0;
    for(int i = 1; i <= q; i++)
    {
        //cout<<t_ans[i]<<endl;
        ans ^= (t_ans[i] * (ll)i);
    }
    printf("%lld",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值