题集链接

目录:

  • OP
  • A Ultra-QuickSort
    • 题目大意
    • 思路
    • 代码
  • B Stars
    • 题目大意
    • 思路
    • 代码
  • C Mobile phones
    • 题目大意
    • 思路
    • 代码
  • D Cows
    • 题目大意
    • 思路
    • 代码
  • E Get Many Persimmon Trees
    • 题目大意
    • 思路
    • 代码
  • F Matrix
    • 题目大意
    • 思路
    • 代码
  • G MooFest
    • 题目大意
    • 思路
    • 代码
  • H Disharmony Trees
    • 思路
    • 代码
  • I KiKi's K-Number
    • 题目大意
    • 思路
    • 代码
  • J Reverse Prime
    • 题目大意
    • 思路
    • 代码
  • ED

OP

感谢学长的讲解与付出;

感谢ph和zsl两位大佬的指导与讨论;

夹带私货:
此节课的代表性的内容已经整理到自己的贴子中:【笔记】数据结构

树状数组总的来说可以快速对数组进行单点更改和区间查询(或通过维护前缀实现区间更改和单点查询),适用于一些边改边查的情况;

A Ultra-QuickSort

题目大意

在一个马桶搋子图片的陪同下 求逆序对;
有定义:若 i < j ,且 a i > a j a_i\gt a_j ai​>aj​ ,则构成一对逆序对;

思路

有两种做法,暂且称之为归并法和树状数组法,大体相同,但树状数组法更加直观,具体做法可以参考PPT,下面简述一下归并法;

在归并排序的过程中,我们会得到两个有序递增数组(暂称为a数组和b数组),其中保证左数组(a)的下标均小于右数组(b);

在通过双指针将两个数组合并时,若对 b j b_j bj​ 存在 a i < b j < a i + 1 a_i\lt b_j\lt a_{i+1} ai​<bj​<ai+1​,则说明 a数组中从 a i + 1 a_{i+1} ai+1​后的每个数都可以和 b j b_j bj​ 构成逆序对;

代码

#include <iostream>using namespace std;
typedef long long ll;
ll a[500005];
ll tmp[500005];
ll ans;
void qs(int l, int r)
{if (l == r)return;int mid = l + r >> 1;qs(l, mid);qs(mid + 1, r);int i = l, j = mid + 1, c = 0;while (i <= mid && j <= r)if (a[i] <= a[j])tmp[c++] = a[i++];elsetmp[c++] = a[j++],ans+=mid-i+1;while (i <= mid)tmp[c++] = a[i++];while (j <= r)tmp[c++] = a[j++];for (i = l, j = 0; i <= r; i ++, j ++ ) a[i] = tmp[j];
}int main()
{int n;while (~scanf("%d", &n) && n){for (int i = 1; i <= n; i++){scanf("%lld", &a[i]);}ans=0;qs(1,n);printf("%lld\n",ans);}
}

B Stars

题目大意

给出星星坐标,求出以每个星星为原点,其第三象限(含象限边界)内的星星数;

思路

由于输入是将星星按先以纵坐标升序,再以横坐标升序顺序输入的,我们可以保证对于新输入的星星,目前在场的所有星星纵坐标皆小于等于它,只需要判断横坐标小于等于它的星星有多少颗即可;

代码

#include <iostream>using namespace std;
typedef long long ll;
int lowbit(int x){return x&-x;}
int c[32003],n=32001,ans[15003];int sum(int x)
{int ans=0;for(;x;x-=lowbit(x))ans+=c[x];return ans;
}
void add(int x,int v)//a[p]+=v;
{for(;x<=n;x+=lowbit(x))c[x]+=v;
}int main()
{int m,x,y;cin>>m;for(int i=1;i<=m;i++){cin>>x>>y;x++,y++;ans[sum(x)]++;add(x,1);}for(int i=0;i<m;i++){printf("%d\n",ans[i]);}
}

C Mobile phones

题目大意

对一个二维平面进行单点数值修改和区块数值总和查询;

思路

模拟

通过二维树状数组维护即可~

板子已经更新到帖子中;

代码

#include <iostream>using namespace std;
typedef long long ll;int c[1025][1025], n = 1024;int lowbit(int x) { return x & -x; }int sum(int x, int y)
{int ans = 0;for (int i = x; i > 0; i -= lowbit(i))for (int j = y; j > 0; j -= lowbit(j))ans += c[i][j];return ans;
}void add(int x, int y, int v) //a[p]+=v;
{for (int i = x; i <= n; i += lowbit(i))for (int j = y; j <= n; j += lowbit(j))c[i][j] += v;
}int main()
{int o, x, y, a, l, b, r, t;while (~scanf("%d", &o) && o != 3){if (o == 1){scanf("%d%d%d", &x, &y, &a);x++, y++;add(x,y, a);}else if (o == 2){scanf("%d%d%d%d", &l, &b, &r, &t);l++, b++, r++, t++;int ans = sum(r,t)-sum(r,b-1)+ sum(l-1,b-1)-sum(l-1,t);printf("%d\n", ans);}else if (o == 0)scanf("%d", &a);}
}

D Cows

题目大意

给出每头牛对应的区间,对每头牛求出有多少个区间覆盖(至多一个端点相同)它的区间;

思路

可以先按右端点降序,左端点升序的顺序排序,若有两区间完全重合,同时保证了两区间排序后必相邻;

排序后对与每头牛,可以保证所有右端点大于其的牛都在它的左侧,如果我们统计的同时在数组中添加该头牛的左端点,则对于每头牛只需要计数目前在其左端点以左有多少个左端点即可;

注意特判重合区间;

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;int c[100005],ans[100005];
int N=100001;
pair<pair<int,int>,int>pir[100005];int lowbit(int x) { return x & -x; }int sum(int x)
{int ans=0;for(;x;x-=lowbit(x))ans+=c[x];return ans;
}void add(int x,int v)//a[x]+=v;
{for(;x<=N;x+=lowbit(x))c[x]+=v;
}bool cmp1(pair<pair<int,int>,int>a,pair<pair<int,int>,int>b)
{if(a.first.second==b.first.second){return a.first.first<b.first.first;}return a.first.second>b.first.second;
}int main()
{int n;while(~scanf("%d",&n)&&n){memset(c,0,sizeof c);for(int i=1;i<=n;i++){scanf("%d%d",&pir[i].first.first,&pir[i].first.second);pir[i].first.first++,pir[i].first.second++;pir[i].second=i;}sort(pir+1,pir+1+n,cmp1);//printf("*");for(int i=1;i<=n;i++){if(pir[i].first==pir[i-1].first)ans[pir[i].second]=ans[pir[i-1].second];elseans[pir[i].second]=sum(pir[i].first.first);add(pir[i].first.first,1);}for(int i=1;i<=n;i++){printf("%d",ans[i]);if(i!=n)printf(" ");else printf("\n");}}
}

E Get Many Persimmon Trees

题目大意

给出总区域大小,每棵树的坐标和可选区域的大小,求所有可选区域中树的最大值;

思路

不需要树状数组,用二维前缀和穷举即可;

做题的时候没意识到这一点,代码中用了树状数组;

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;int c[102][102], X = 100,Y=100;int lowbit(int x) { return x & -x; }int sum(int x, int y)
{int ans = 0;for (int i = x; i > 0; i -= lowbit(i))for (int j = y; j > 0; j -= lowbit(j))ans += c[i][j];return ans;
}void add(int x, int y, int v) //a[x][y]+=v;
{for (int i = x; i <= X; i += lowbit(i))for (int j = y; j <= Y; j += lowbit(j))c[i][j] += v;
}int main()
{int n;int w,h,x,y,s,t;while(~scanf("%d",&n)&&n){memset(c,0,sizeof c);scanf("%d%d",&w,&h);for(int i=1;i<=n;i++){scanf("%d%d",&x,&y);add(x,y,1);}scanf("%d%d",&s,&t);int ans=0;for(int i=s;i<=w;i++){for(int j=t;j<=h;j++){ans=max(ans,sum(i,j)-sum(i-s,j)+sum(i-s,j-t)-sum(i,j-t));}}printf("%d\n",ans);}
}

F Matrix

题目大意

二维区间修改,单点查询;

思路

可以通过树状数组维护二位前缀和实现;

实际上不需要做翻转的动作,只需要判断奇偶即可;

注意输出要求;

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;int c[1003][1003], X = 1000, Y = 1000;int lowbit(int x) { return x & -x; }int sum(int x, int y)
{int ans = 0;for (int i = x; i > 0; i -= lowbit(i))for (int j = y; j > 0; j -= lowbit(j))ans += c[i][j];return ans;
}void add(int x, int y, int v) //a[x][y]+=v;
{for (int i = x; i <= X; i += lowbit(i))for (int j = y; j <= Y; j += lowbit(j))c[i][j] += v;
}int main()
{int t, n, x, x1, y1, x2, y2;char o;cin >> t;while (t--){scanf("%d%d", &n, &x);memset(c, 0, sizeof c);for (int i = 1; i <= x; i++){cin>>o;if (o == 'C'){scanf("%d%d%d%d", &x1, &y1, &x2, &y2);add(x1, y1, 1);add(x2 + 1, y2 + 1, 1);add(x1, y2 + 1, -1);add(x2 + 1, y1, -1);}else if (o == 'Q'){scanf("%d%d", &x1, &y1);printf("%d\n", sum(x1, y1) & 1);}}printf("\n");}
}

G MooFest

题目大意

给定每头牛的位置 x i x_i xi​和音量 v i v_i vi​,定义两牛 i , j i,j i,j交流所需要的代价为 a b s ( x i − x j ) ⋅ m a x ( v i , v j ) abs(x_i-x_j)\cdotp max(v_i,v_j) abs(xi​−xj​)⋅max(vi​,vj​),求所有牛对(N(N-1)/2对)进行互相交流的总代价;

思路

我们可以按v升序排序,可以保证每头牛j 和前面交流时的 m a x ( v i , v j ) = v j max(v_i,v_j)=v_j max(vi​,vj​)=vj​;

接下来需要处理 a b s ( x i − x j ) abs(x_i-x_j) abs(xi​−xj​):
我们可以维护前面所有牛的坐标和 s u m x sumx sumx ,再通过树状数组求出前面牛中比此牛坐标小的坐标之和 s s s 和头数 k k k ;
那么此时的 ∑ i = 1 i < j a b s ( x i − x j ) = s u m x − s − x j ⋅ ( j − 1 − k ) + x j ⋅ k − s \sum_{i=1}^{i<j}abs(x_i-x_j)=sumx-s-x_j\cdotp (j-1-k)+x_j\cdotp k-s ∑i=1i<j​abs(xi​−xj​)=sumx−s−xj​⋅(j−1−k)+xj​⋅k−s;

即可求出此牛和前面所有牛交流所用代价;

代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;pair<int,ll> c[20004];
int N=20000;
pair<int,ll>pir[20004];
int lowbit(int x) { return x & -x; }pair<int,ll> sum(int x)
{pair<int,ll> ans =make_pair(0,0);for (int i = x; i > 0; i -= lowbit(i))ans.second += c[i].second,ans.first+=c[i].first;return ans;
}void add(int x, pair<int,ll> v) //a[x][y]+=v;
{for (int i = x; i <=N; i += lowbit(i))c[i].first += v.first,c[i].second+=v.second;
}int main()
{int n;cin>>n;for(int i=1;i<=n;i++){scanf("%d%lld",&pir[i].first,&pir[i].second);}sort(pir+1,pir+1+n);ll sumx=0,ans=0;for(int i=1;i<=n;i++){pair<int,ll>res=sum(pir[i].second);ans+=pir[i].first*((sumx-res.second-pir[i].second*((i-1)-res.first))+pir[i].second*res.first-res.second);add(pir[i].second,make_pair(1,pir[i].second));sumx+=pir[i].second;}printf("%lld\n",ans);
}

H Disharmony Trees

思路

和G类似~

另外地,此题需要将坐标和高度转换为顺序;

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;pair<ll,ll> c[100005];
pair<pair<ll,ll>,pair<ll,ll> > te[100005];//<x,h>
int N = 100000;int lowbit(int x) { return x & -x; }pair<ll,ll> sum(int x)
{pair<ll,ll> ans = make_pair(0,0);for (int i = x; i > 0; i -= lowbit(i))ans.second += c[i].second,ans.first+=c[i].first;return ans;
}void add(int x,int v)
{for (int i = x; i <= N; i += lowbit(i))c[i].second += v,c[i].first++;
}bool cmp(pair<pair<ll,ll>,pair<ll,ll> >a,pair<pair<ll,ll>,pair<ll,ll> >b)
{return a.first.second<b.first.second;
}int main()
{int n;while(~scanf("%d",&n)){memset(c,0,sizeof c);for(int i=1;i<=n;i++){scanf("%lld%lld",&te[i].first.first,&te[i].first.second);}sort(te+1,te+1+n);for(int i=1;i<=n;i++){if(te[i].first.first==te[i-1].first.first){te[i].second.first=te[i-1].second.first;}else te[i].second.first=i;}sort(te+1,te+1+n,cmp);for(int i=1;i<=n;i++){if(te[i].first.second==te[i-1].first.second){te[i].second.second=te[i-1].second.second;}else te[i].second.second=i;}ll ans=0,sumx=0;for(int i=n;i>=1;i--){pair<ll,ll>tmp=sum(te[i].second.first);ans+=(sumx-tmp.second-te[i].second.first*(n-i-tmp.first)+tmp.first*te[i].second.first-tmp.second)*te[i].second.second;sumx+=te[i].second.first;add(te[i].second.first,te[i].second.first);}printf("%lld\n",ans);}
}

I KiKi’s K-Number

题目大意

对于一个容器,有三种操作:
加入数字e,删除数字e,查询大于a的第k个数;

思路

大体上可以用桶排的思路进行加入和删除维护;

对于查询,我们可以使用二分的思想快速确定;

具体看代码~

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;int c[100005], N = 100001;int lowbit(int x) { return x & -x; }int sum(int x)
{int ans = 0;for (int i = x; i > 0; i -= lowbit(i))ans += c[i];return ans;
}void add(int x,int v) //a[x][y]+=v;
{for (int i = x; i <= N; i += lowbit(i))c[i] += v;
}int main()
{int m,p,e,k;while (~scanf("%d",&m)){memset(c,0,sizeof c);while(m--){scanf("%d%d",&p,&e);e++;if(p==0){add(e,1);}else if(p==1){if(sum(e)-sum(e-1)){add(e,-1);}else printf("No Elment!\n");}else{scanf("%d",&k);int l=e,r=N+1;while(l<r){int mid=l+r>>1;if(sum(mid)-sum(e)>=k)r=mid;else l=mid+1;}if(l==N+1)printf("Not Find!\n");else printf("%d\n",l-1);}}}
}

J Reverse Prime

题目大意

定义了“反向指数”,要求进行两种操作:
删除反向质数e,查询前 i 个反向质数的质因数数量之和;

思路

具体查询过程和 I 题类似;

对于一个被删除的的反向质数,我们可以标记删除,并在维护质因数数量的树状数组中的那一位清零(删除等量的质因数);
对于查询操作,使用二分思想,找到该位之前满足剩余 i 个的位置;

代码

#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <map>
using namespace std;
typedef long long ll;int c[80004],N = 78500 , del[80004];int lowbit(int x) { return x & -x; }ll sum(int* c,int x)
{ll ans =0;for (int i = x; i > 0; i -= lowbit(i))ans += c[i];return ans;
}void add(int *c,int x,int v)
{for (int i = x; i <= N; i += lowbit(i))c[i]+= v;
}int n[1000006],p[80004],ct[80004],rp[80004];
map<int,int>mp;
int main()
{int cp=0;for(int i=2;i<1000000;i++){if(!n[i])p[cp++]=i;for(int j=0;j<cp&&p[j]*i<1000000;j++){n[p[j]*i]=1;if(i%p[j]==0)break;}}for(int i=0;i<cp;i++){ll as=0,tmp=p[i];for(tmp;tmp;tmp/=10){as*=10,as+=tmp%10;}while(as<1000000)as*=10;rp[i+1]=as;}sort(rp+1,rp+cp+1);for(int i=1;i<=cp;i++){ll as=rp[i];//printf("%d\n",as);mp[as]=i;for(int j=0;p[j]<=sqrt(as)&&j<cp;j++){while(as%p[j]==0){as/=p[j];ct[i]++;}}if(as>1)ct[i]++;add(c,i,ct[i]);}//printf("%d",ct[1]);char o;int x;while(cin>>o){scanf("%d",&x);if(o=='d'){int i=mp[x];mp[x]=0;if(!i)continue;add(del,i,1);add(c,i,-ct[i]);}else{x++;if(x>78498)x=78498;int l=x,r=78499;while(l<r){int mid=l+r>>1;if(mid-sum(del,mid)>=x)r=mid;else l=mid+1;}printf("%lld\n",sum(c,l));}}
}

ED

\

NEFU大一暑假集训-树状数组相关推荐

  1. 简单の暑假总结——树状数组

    2.1 树状数组 树状数组,顾名思义,长得像树的数组,用于处理一些单点修改以及区间查询的问题.其时间复杂度为 O(log⁡2n)O(\log _2n)O(log2​n) .如过我们使用一些一般的数据结 ...

  2. 暑假集训总结——区间DP,堆的概念及应用,STL(vector、set、pair、map、priority_queue),hash表,树状数组,图论

    序言: 经过长达十几天的集训,确实学了不少知识点.我想如果再不总结的话,6天之后又要忘完了. 所以发一篇具有总结回忆性的博客,供大家回忆. 目录会本人自己排列的时间的先后顺序来排列,可直接食用. 目录 ...

  3. 2023牛客寒假算法基础集训营4_20230130「向上取整」「夹逼dp」「lowbit科学+树状数组性质」「搜索」「倍增跳表」「莫队」

    6/13 教育场是有被教育到.(预计会鸽几题. 已过非太水的题们 //B //https://ac.nowcoder.com/acm/contest/46812/B//小构造小数学#include & ...

  4. Educational Codeforces Round 80 (Rated for Div. 2)SZU cf集训round2 C~E(dp,状压+二分,树状数组+逆向思维)

    C. Two Arrays 题目大意:就是给定两个整数n和m.计算数组对的数量(a,b),使得: 1 .两个阵列的长度都等于m: 2 .每个数组的每个元素都是1到n(包括1和n)之间的整数: 从1到m ...

  5. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+LCT+树状数组)

    description 点击查看题目内容 solution Step1 无脑建SAMSAMSAM 两个前缀的最长公共后缀就是parent−treeparent-treeparent−tree上两点的l ...

  6. UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】

    题目分析: 这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案. 我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$. 合并 ...

  7. 集训8.21树状数组讲解

    有点想家了... 树状数组的用途:单点更新,区间查询(如敌兵布阵) 区间更新,单点查询(如color the ball) 一维树状数组: int lowbit(int x) {     return ...

  8. acwing 297. 赤壁之战 树状数组优化DP 寒假集训

    题目链接 想要求长度为M的子序列,我们可以拿DP方程来计算,并且这个DP也是比较好看出来的DP[i][j]代表着i后j位置中的所有长度为j的子序列,递推方程为 for(int i=1;i<=n; ...

  9. 2019hdu暑假多校训练赛第九场1002 Rikka with Cake hdu6681(树状数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6681 题意:给定一个n*m的蛋糕,再给出K个操作,每次都是从蛋糕的中间向四个方向中的一个切过去,问最后 ...

最新文章

  1. oracle迁移postsql的,osdba's blog : Oracle迁移PostgreSQL系列文章之二:merge语句
  2. ssh中exit命令退出远程服务器_解决Linux关闭终端(关闭SSH等)后运行的程序或者服务自动停止...
  3. SWIFT推送之本地推送(UILocalNotification)之二带按钮的消息
  4. Mysql 5.5的编译安装 在ubuntu 10平台上面
  5. 有用的Copy-On-write,写时复制
  6. django 用户认证
  7. (重读)JavaScript高级程序设计第四版
  8. android imagebutton 动画,android – ImageButton Icon Tint基于State
  9. UA OPTI512R 傅立叶光学导论1 为什么光学需要傅立叶变换
  10. 关于阿里云短信验证服务完整的教程
  11. Mixly-数位计及1602屏亮度显示
  12. java.util.timer_java.util.Timer分析源码了解原理
  13. kindle DXG 安装多看
  14. html 输入字数限制,说一说限制字数的输入框踩的坑
  15. 阿里云主机(ECS)入门(图文说明)详细了解
  16. java 二次封装azkaban 实现azkaban任务的执行
  17. 笔记整理--玩转robots协议
  18. python 删除特定列_pandas删除某一列的方法(drop函数)
  19. 这款小巧精致的 Keychron K7 满足了我对键盘的所有想象
  20. 爱国者新品发布 智能果汁机助力双创 居家创业双赢新产能

热门文章

  1. Flutter 读写文件
  2. Cesium地图暗色滤镜
  3. 拳皇命运微信1区提示服务器爆满,拳皇命运iOS微信9区轰斧阴开服时间表_拳皇命运新区开服预告_第一手游网手游开服表...
  4. Mysql导出数据库,导出视图
  5. P82-前端基础动画效果-动画旋转练习鸭子表
  6. Excel表格无法写入文字怎么解决
  7. vue-axios的application/x-www-form-urlencod的post请求无法解析参数
  8. java中long转int的原理
  9. Java中int和long数据类型转换及溢出问题
  10. c语言的argv,C语言的Argv的使用