HDU 5930 GCD
来源:互联网 发布:javac 多个java文件 编辑:程序博客网 时间:2024/06/18 07:41
HDU 5930 GCD
线段树上二分
题意
设计数据结构支持:
- 单点修改
- 查询整个区间以及每个子区间有多少种不同的区间gcd
思路
线段树上的二分。
%%%
大体思路是这样:初始区间给定后,可以计算出每个gcd有多少个区间,用g数组记录一下。(因为最大的数字不超过1000000)
线段树维护区间gcd。每次修改,假设修改pos处的值,先计算所有受pos影响的区间的gcd与个数,在g数组上减去这些;在线段树单点修改pos的值,重复上述操作,在g数组上加回来。
问题就是怎么计算受pos影响的区间的gcd。两个query函数的变种:queryl(pos,gcdval,l,r,rt)
与queryr(pos,gcdval,l,r,rt)
。负责查询pos处左侧(右侧)第一个与gcdval不同的gcd的值以及位置,亦即以pos为右(左)端点的直到数列尽头的,每个gcd不同的区间。这样每次查的结果存到数组,pos左侧存一个数组,pos右侧存一个数组,最后两个数组组合一下,更新g。
以queryl
为例,说一下:
//查询时//R落在[l,mid],这时直接递归到左儿子//R落在[mid+1,r],这时先查一下右儿子,如果gcd小于p,说明gcd变化了,那么返回查询结果//如果gcd>=p,说明目前查到的[mid+1,pos]这些数都是pos这数的倍数,gcd没有变化,要再查左儿子//递归基有两种情况,某个完全在左侧的区间的公约数%p==0,说明这些数全比pos处大,直接返回p就行,或者查到了叶子,也要返回//感觉好复杂,自己理解吧pair<int, int> queryl(int R, int p, int l, int r, int rt){ if(r<=R) { if(stree[rt]%p==0) return make_pair(p, l); else if(l==r) return make_pair(gcd(p, stree[rt]), l);//l实际改成1也能过,是一样的 } int mid=(l+r)>>1; if(R<=mid) return queryl(R, p, lson); pair<int, int> tmp=queryl(R, p, rson); if(tmp.first<p) return tmp; return queryl(R, p, lson);}
对了,初始统计g数组时也用了上面的方法。
代码
不知道以后遇到这种题能不能写得出来
#include <bits/stdc++.h>#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define M(a,b) memset(a,b,sizeof(a))using namespace std;const int MAXN=50005, MAXG=1000007;int stree[MAXN<<2], num[MAXN];int g[MAXG];inline int gcd(int a, int b) { return b==0 ? a : gcd(b, a%b); }inline void pushup(int rt) { stree[rt]=gcd(stree[rt<<1], stree[rt<<1|1]); }void build(int l, int r, int rt){ if(l==r) { stree[rt]=num[l];return; } int mid=(l+r)>>1; build(lson); build(rson); pushup(rt);}void update(int pos, int val, int l, int r, int rt){ if(l==r) { stree[rt]=val; return; } int mid=(l+r)>>1; if(pos<=mid) update(pos, val, lson); else update(pos, val, rson); pushup(rt);}int query(int L, int R, int l, int r, int rt){ if(L<=l&&r<=R) return stree[rt]; int mid=(l+r)>>1; if(mid>=R) return query(L, R, lson); else if(L>mid) return query(L, R, rson); else return gcd(query(L, R, lson), query(L, R, rson));}pair<int, int> queryl(int R, int p, int l, int r, int rt){ if(r<=R) { if(stree[rt]%p==0) return make_pair(p, l); else if(l==r) return make_pair(gcd(p, stree[rt]), l); } int mid=(l+r)>>1; if(R<=mid) return queryl(R, p, lson); pair<int, int> tmp=queryl(R, p, rson); if(tmp.first<p) return tmp; return queryl(R, p, lson);}pair<int, int> queryr(int L, int p, int l, int r, int rt){ if(L<=l) { if(stree[rt]%p==0) return make_pair(p, l); else if(l==r) return make_pair(gcd(p, stree[rt]), l); } int mid=(l+r)>>1; if(L>mid) return queryr(L, p, rson); pair<int, int> tmp=queryr(L, p, lson); if(tmp.first<p) return tmp; return queryr(L, p, rson);}void calc(int p, int f, int &s, int n){ vector<pair<int, int>> pl, pr; int nowgcd, finalgcd, curpos; nowgcd=num[p], finalgcd=query(1, p, 1, n, 1), curpos=p; pl.push_back(make_pair(nowgcd, p)); while(nowgcd!=finalgcd) { pair<int, int> tmp=queryl(curpos, nowgcd, 1, n, 1); pl.push_back(tmp); nowgcd=tmp.first, curpos=tmp.second; } pl.push_back(make_pair(nowgcd, 0)); nowgcd=num[p], finalgcd=query(p, n, 1, n, 1), curpos=p; pr.push_back(make_pair(nowgcd, p)); while(nowgcd!=finalgcd) { pair<int, int> tmp=queryr(curpos, nowgcd, 1, n, 1); pr.push_back(tmp); nowgcd=tmp.first, curpos=tmp.second; } pr.push_back(make_pair(nowgcd, n+1)); for(int i=1;i<pl.size();i++) { int lenl=pl[i-1].second-pl[i].second; int gcdl=pl[i-1].first; for(int j=1;j<pr.size();j++) { int lenr=pr[j].second-pr[j-1].second; int gcdr=pr[j-1].first; int num=f*lenl*lenr; int tmpgcd=gcd(gcdl, gcdr); if(g[tmpgcd]==0) s++; g[tmpgcd]+=num; if(g[tmpgcd]==0) s--; } }}int main(){ int T; scanf("%d", &T);int cas=0; while(T--) { printf("Case #%d:\n", ++cas); int gcdsum=0; M(g, 0); int n, op;scanf("%d%d", &n, &op); for(int i=1;i<=n;i++) scanf("%d", &num[i]); build(1, n, 1); for(int i=1;i<=n;i++) { int nowgcd=num[i], finalgcd=query(1, i, 1, n, 1), curpos=i; while(nowgcd!=finalgcd) { pair<int, int> tmp=queryl(curpos, nowgcd, 1, n, 1); if(!g[nowgcd]) gcdsum++; g[nowgcd]+=curpos-tmp.second; nowgcd=tmp.first, curpos=tmp.second; } if(!g[finalgcd]) gcdsum++; g[finalgcd]+=curpos; } while(op--) { int p, v;scanf("%d%d", &p, &v); calc(p, -1, gcdsum, n); num[p]=v; update(p, v, 1, n, 1); calc(p, 1, gcdsum, n); printf("%d\n", gcdsum); } } return 0;}
阅读全文
0 0
- HDU 5930 GCD
- HDU 5930GCD
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- GCD HDU
- 【HDU】5930 GCD【暴力+线段树二分】
- hdu--1787---gcd again
- hdu 1787 GCD again
- HDU 1695 GCD 数论
- HDU 2588 GCD
- hdu-又见GCD
- 字符流中第一个不重复的字符
- SpringMvc是单例还是多例?
- docker centos7 安装ssh等基础软件
- AGM函数近似值的估计
- 到底怎么获取积分啊.只能做VIP菜有积分吗?
- HDU 5930 GCD
- org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.lin
- 黑帽之家蜘蛛池
- c语言初步经典题---计算长方形的周长和面积
- 域名信息521js破解
- Server 2012 域用户添加本地管理员权限
- Servlet中HttpSession
- volatile在i++情况下失效
- mybatis映射文件中sql语句符号问题