题意:

  给一个数列,一些询问,问你$[l,r]$之间不同的数字之和

题解:

  11年多校的题,现在属于"人尽皆知傻逼题"

  核心思想在于:  对于一个询问$[x,R]$ 无论$x$是什么,整个数列中,对于答案有贡献的,只有每种数字中,$R$左边最近的一个

  对于数列$1,1,2,2,3,3,4,4,1,1,2,2,4,3,4,5,5,P...$和

           $0,0,0,0,0,0,0,0,0,1,0,2,0,3,4,0,5,P...$ 只要右边界保持在P-1,询问结果是等价的

具体操作就是,存储询问,按R排序,依次处理,删除当前询问R之前所有的,只保存最后一个

用线段树,树状数组都行,做单点修改区间查询就行..

bit

#include <bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pp pair<int,int>
#define rep(ii,a,b) for(int ii=a;ii<=b;ii++)
#define per(ii,a,b) for(int ii=a;ii>=b;ii--)
using namespace std;
const int maxn=1e6+10;
const int maxm=1e6*4+10;
const int INF=0x3f3f3f3f;
int casn,n,m,k;
#define lb(x) x&-x
ll bit[maxn],num[maxn];
void update(int pos,int x){
while(pos<=n){
bit[pos]+=x,pos+=lb(pos);
}
}
ll sum(int pos){
ll ans=0;
while(pos){
ans+=bit[pos],pos-=lb(pos);
}
return ans;
}
ll query(int a,int b){
return sum(b)-sum(a-1);
}
struct node2 {
int l,r,id;
}ask[maxn];
int cmp(node2 a,node2 b){
return a.r<b.r;
}
map<ll,int>pos;
ll ans[maxn];
int main(){
//#define test
#ifdef test
freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
scanf("%d",&casn);
while(casn--){
scanf("%d",&n);
rep(i,1,n) bit[i]=0;
for(int i=1;i<=n;i++){
scanf("%lld",num+i);
update(i,num[i]);
}
pos.clear();
scanf("%d",&k);
int a,b;
for(int i=1;i<=k;i++){
scanf("%d%d",&a,&b);
ask[i]=(node2){a,b,i};
}
sort(ask+1,ask+1+k,cmp);
int r=1;
for(int i=1;i<=k;i++){
while(r<=ask[i].r){
if(pos[num[r]]){
update(pos[num[r]],-num[r]);
}
pos[num[r]]=r;
r++;
}
ans[ask[i].id]=query(ask[i].l,ask[i].r);
}
for(int i=1;i<=k;i++){
printf("%lld\n",ans[i]);
}
} #ifdef test
fclose(stdin);fclose(stdout);system("out.txt");
#endif
return 0;
}

线段树

#include <bits/stdc++.h>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pp pair<int,int>
#define rep(ii,a,b) for(int ii=a;ii<=b;ii++)
#define per(ii,a,b) for(int ii=a;ii>=b;ii--)
using namespace std;
const int maxn=1e5+10;
const int maxm=1e6+10;
const int INF=0x3f3f3f3f;
int casn,n,m,k;
#define nd lst[now]
struct node {
int l,r;ll sum;
}lst[maxm];
ll num[maxn];
void maketree(int s=1,int t=n,int now=1){
nd=(node){s,t,num[s]};
if(s==t) return ;
maketree(s,(s+t)>>1,now<<1);
maketree(((s+t)>>1)+1,t,now<<1|1);
nd.sum=lst[now<<1].sum+lst[now<<1|1].sum;
}
inline void pushup(int now) {
nd.sum=lst[now<<1].sum+lst[now<<1|1].sum;
}
void update(int pos,int x,int now=1){
if(pos<nd.l||pos>nd.r) return ;
if(nd.r==nd.l){
nd.sum=x;
return;
}
update(pos,x,now<<1);
update(pos,x,now<<1|1);
pushup(now);
}
ll query(int s,int t,int now=1){
if(s>nd.r||t<nd.l) return 0;
if(s<=nd.l&&t>=nd.r) return nd.sum;
return query(s,t,now<<1)+query(s,t,now<<1|1);
}
struct node2 {
int l,r,id;
}ask[maxn];
int cmp(node2 a,node2 b){
return a.r<b.r;
}
map<ll,int>pos;
ll ans[maxn];
int main(){
#define test123
#ifdef test
freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endif
scanf("%d",&casn);
while(casn--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",num+i);
}
pos.clear();
maketree();
scanf("%d",&k);
int a,b;
for(int i=1;i<=k;i++){
scanf("%d%d",&a,&b);
ask[i]=(node2){a,b,i};
}
sort(ask+1,ask+1+k,cmp);
int r=1;
for(int i=1;i<=k;i++){
while(r<=ask[i].r){
if(pos[num[r]]){
update(pos[num[r]],0);
}
pos[num[r]]=r;
r++;
}
ans[ask[i].id]=query(ask[i].l,ask[i].r);
}
for(int i=1;i<=k;i++){
printf("%lld\n",ans[i]);
}
} #ifdef test
fclose(stdin);fclose(stdout);system("out.txt");
#endif
return 0;
}

HDU 3333 Turing Tree 离线 线段树/树状数组 区间求和单点修改的更多相关文章

  1. hdu 3333 Turing Tree(线段树+离散化)

    刚看到是3xian大牛的题就让我菊花一紧,觉着这题肯定各种高端大气上档次,结果果然没让我失望. 刚开始我以为是一个普通的线段树区间求和,然后啪啪啪代码敲完测试没通过,才注意到这个求和是要去掉相同的值的 ...

  2. Hdu 5862 Counting Intersections(有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点+树状数组区间求和单点跟新)

    传送门:Hdu 5862 Counting Intersections 题意:有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点 分析: 基本的操作流程是:先将所有的线段按照横树坐标x按小的 ...

  3. hdu 1116 敌兵布阵(树状数组区间求和)

    题意: 给出一行数字,然后可以修改其中第i个数字,并且可以询问第i至第j个数字的和(i <= j). 输入: 首行输入一个t,表示共有t组数据. 接下来每行首行输入一个整数n,表示共有n个数字. ...

  4. HDU 3333 Turing Tree 线段树+离线处理

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Othe ...

  5. hdu 3333 Turing Tree 图灵树(线段树 + 二分离散)

    http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Others)    ...

  6. 【poj2155】Matrix(二维树状数组区间更新+单点查询)

    Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the ...

  7. HDU 3333 Turing Tree (线段树)

    Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  8. HDU 3333 - Turing Tree (树状数组+离线处理+哈希+贪心)

    题意:给一个数组,每次查询输出区间内不重复数字的和. 这是3xian教主的题. 用前缀和的思想可以轻易求得区间的和,但是对于重复数字这点很难处理.在线很难下手,考虑离线处理. 将所有查询区间从右端点由 ...

  9. HDU 3333 Turing Tree(离线树状数组)

    Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

随机推荐

  1. Java 微信公众号导出所有粉丝(openId)

    由于公众号换了公司主体,需要做迁移,玩家的openId数据需要做处理. (我是按我要的json格式,将粉丝导成了1万条数据的一个json文件) 文件格式: { "info":[ { ...

  2. 微服务之consul

    一.概述 consul是google开源的一个使用go语言开发的服务发现.配置管理中心服务.内置了服务注册与发现框 架.分布一致性协议实现.健康检查.Key/Value存储.多数据中心方案,不再需要依 ...

  3. ORM常用字段和参数

    目录: ORM常用字段和参数

  4. jQuery使用(四):DOM操作之查找兄弟元素和父级元素

    查找兄弟元素 向下查找兄弟元素 next() nextAll() nextUntil() 向上查找兄弟元素 prev() prevAll() prevUntil() 查找所有兄弟元素 siblings ...

  5. Idea每次修改jsp都需要重启tomcat解决方法

  6. HDU 6373(斜面上小球弹跳 运动分解)

    题意是给定两个点的位置,过原点引一条射线穿过第一个点,射线位置作为斜面位置,第二个点处令一小球自由落体,问小球能碰撞到斜面几次. 开始时想算出两次碰撞中小球沿斜面运动的距离,然后发现每一段距离会因为高 ...

  7. LeetCode(192. Word Frequency)

    192. Word Frequency Write a bash script to calculate the frequency of each word in a text file words ...

  8. javascript&&jquery编写插件模板

    javascrpt插件编写模板 这里不分享如何编写插件,只留一个框架模板,使用面向对象的形式进行编写,方便管理 ;(function(window,document){ function FnName ...

  9. Python获取下载速度并显示进度条

    #!/usr/bin/python3 # -*- coding:utf-8 -*- import sys import time from urllib import request ''' urll ...

  10. jsp查询修改

    也是只帖代码....不讲解. 1.search.jsp <%@ page language="java" import="java.util.*" pag ...