Processing math: 100%

题解 P3567 [POI2014]KUR-Couriers

题意翻译

给一个长度为 n 的正整数序列 a。共有 m 组询问,每次询问一个区间 [l,r] ,是否存在一个数在[l,r] 中出现的次数严格大于一半。如果存在,输出这个数,否则输出 0

1n,m5×1050ain.

分析

是主席树的板子题,不过用莫队也可以做。

这里讲一下主席树的做法。(其实也没有什么做法)。。

利用前缀和的性质,我们可以得到 [L,R] 中的元素组成的权值线段树。

从根节点开始,

我们假设存在 该严格众数。

那么

  • 该数的出现次数 >(rl+1)/2 ----------> 该数所在区间的 sum>(rl+1)/2
  • 又某节点的左右子树中至多只有一个满足该性质,(总共才 (rl+1) 个元素)。
  • 所以,如果有子树满足该性质,那么往这个子树走,
  • 如果一个都没有,那么不存在严格众数,返回0.

Code:

copy
#include<vector> #include<cstdio> #include<iostream> #include<algorithm> #define LL long long #define rint register int using namespace std; namespace FastIO { char c; bool sign; template<class T> inline void read(T &x) { x=0; sign=false; for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') sign=true; for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c&15); if(sign) x=~x+1; return; } template<class T> void print(T x) { if(x<0) putchar('-'),x=~x+1; if(x>9) print(x/10); putchar(x%10+'0'); return; } } using FastIO::read; using FastIO::print; //================================================ const int N=5e5+5; struct Node { int lc,rc; int sum; }hjt[32*N]; int cnt=0; int root[N]; void insert(int &now,const int &pre,const int &key,const int &l,const int &r) { hjt[now=++cnt]=hjt[pre]; hjt[now].sum++; if(l==r) return; int mid=(l+r)>>1; if(key<=mid) insert(hjt[now].lc,hjt[pre].lc,key,l,mid); else insert(hjt[now].rc,hjt[pre].rc,key,mid+1,r); return; } int query(const int &L,const int &R,const int &l,const int &r,const int &lit) //(L,R] { if(l==r) return l; int mid=(l+r)>>1; if(hjt[hjt[R].lc].sum-hjt[hjt[L].lc].sum>lit) return query(hjt[L].lc,hjt[R].lc,l,mid,lit); else if(hjt[hjt[R].rc].sum-hjt[hjt[L].rc].sum>lit) return query(hjt[L].rc,hjt[R].rc,mid+1,r,lit); else return 0; } int a[N]; int n,m; vector<int> v; int main() { // freopen("1.in","r",stdin); rint i; int x,y,z; read(n); read(m); for(i=1;i<=n;i++) { read(a[i]); v.push_back(a[i]); } sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); for(i=1;i<=n;i++) a[i]=(int)(lower_bound(v.begin(),v.end(),a[i])-v.begin())+1; for(i=1;i<=n;i++) insert(root[i],root[i-1],a[i],1,v.size()); while(m--) { read(x); read(y); z=query(root[x-1],root[y],1,v.size(),(y-x+1)>>1); if(z==0) puts("0"); else print(v[z-1]),putchar('\n'); } return 0; }

虽然题目的数据范围不需要离散化,但我还是离散化了一下,(但愿会快一点)。

另外第一次用 scanfprintf 交上去T了,

5×105 的数据范围下,用快读快输大概会比 scanf printf 稳定的快上 100ms150ms


P.S:还有两种很巧妙的做法。

posted @   cjlworld  阅读(175)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起