HDU 3333 Turing Tree 离线 线段树/树状数组 区间求和单点修改
题意:
给一个数列,一些询问,问你$[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 离线 线段树/树状数组 区间求和单点修改的更多相关文章
- hdu 3333 Turing Tree(线段树+离散化)
刚看到是3xian大牛的题就让我菊花一紧,觉着这题肯定各种高端大气上档次,结果果然没让我失望. 刚开始我以为是一个普通的线段树区间求和,然后啪啪啪代码敲完测试没通过,才注意到这个求和是要去掉相同的值的 ...
- Hdu 5862 Counting Intersections(有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点+树状数组区间求和单点跟新)
传送门:Hdu 5862 Counting Intersections 题意:有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点 分析: 基本的操作流程是:先将所有的线段按照横树坐标x按小的 ...
- hdu 1116 敌兵布阵(树状数组区间求和)
题意: 给出一行数字,然后可以修改其中第i个数字,并且可以询问第i至第j个数字的和(i <= j). 输入: 首行输入一个t,表示共有t组数据. 接下来每行首行输入一个整数n,表示共有n个数字. ...
- HDU 3333 Turing Tree 线段树+离线处理
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Othe ...
- hdu 3333 Turing Tree 图灵树(线段树 + 二分离散)
http://acm.hdu.edu.cn/showproblem.php?pid=3333 Turing Tree Time Limit: 6000/3000 MS (Java/Others) ...
- 【poj2155】Matrix(二维树状数组区间更新+单点查询)
Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the ...
- HDU 3333 Turing Tree (线段树)
Turing Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- HDU 3333 - Turing Tree (树状数组+离线处理+哈希+贪心)
题意:给一个数组,每次查询输出区间内不重复数字的和. 这是3xian教主的题. 用前缀和的思想可以轻易求得区间的和,但是对于重复数字这点很难处理.在线很难下手,考虑离线处理. 将所有查询区间从右端点由 ...
- HDU 3333 Turing Tree(离线树状数组)
Turing Tree Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
随机推荐
- css3 transition和animation的区别与联系
1. transition 一定时间之内,一组css属性变换到另一组属性的动画展示过程. 属性: transition-property:动画展示哪些属性,可以使用all关键字: transition ...
- VScode-Common-Shortcut
Keyboard shortcuts for windows Keyboard Shortcut For Windows General Shortcut Commands Ctrl + Shift ...
- HDU 6433(2的n次方 **)
题意是就是求出 2 的 n 次方. 直接求肯定不行,直接将每一位存在一个数组的各个位置即可,这里先解出 2 的 n 次方的位数,再直接模拟每一位乘以 2 即可得到答案. 求解 2 的 n 次方的位数的 ...
- HDU 6375(双端队列 ~)
题意是有至多150000个双端队列,400000次简单操作,直接开会导致内存超限,所以用 STL 中的 map 和 deque ,而读入过大已经在题目中有所说明,直接用已经给出的快速读入即可.要注意的 ...
- Docker 从入门到放弃(一)安装
前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任 ...
- IO流之FileUtils工具类的使用
IO流之FileUtils工具类的使用: 使用apache的commons-io包下的FileUtils,我筛选了一些常用方法:
- keeping.py
定时push+告警 #!/usr/bin/env python # -*- coding:utf-8 -*- # Author : 71standby@gmail.com # Description ...
- linux 操作 json文件
Linux 下 操作 json 文件神器 jq. jq yum install jq -y 查看一个 file.json 文件 # jq . file.json JSON (JavaScript O ...
- IIS服务器的安全保护措施
转载自:https://www.williamlong.info/archives/118.html 部分内容做了修改. 通过标注Web服务器安全级别以及可用性的安全策略,网络管理员将能够从容地在不同 ...
- react编译报错:Import in body of module; reorder to top import/first
原因是这样的: 我把一个组件分为三个文件, |—Home.jsx // 业务逻辑与html Home——|—Home.css // 样式 |—index.js // 引入Home.css ,再把Hom ...